PostgreSQL Source Code  git master
joinpath.c File Reference
#include "postgres.h"
#include <math.h>
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
Include dependency graph for joinpath.c:

Go to the source code of this file.

Macros

#define PATH_PARAM_BY_PARENT(path, rel)
 
#define PATH_PARAM_BY_REL_SELF(path, rel)   ((path)->param_info && bms_overlap(PATH_REQ_OUTER(path), (rel)->relids))
 
#define PATH_PARAM_BY_REL(path, rel)   (PATH_PARAM_BY_REL_SELF(path, rel) || PATH_PARAM_BY_PARENT(path, rel))
 

Functions

static void try_partial_mergejoin_path (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, List *mergeclauses, List *outersortkeys, List *innersortkeys, JoinType jointype, JoinPathExtraData *extra)
 
static void sort_inner_and_outer (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
 
static void match_unsorted_outer (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
 
static void consider_parallel_nestloop (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
 
static void consider_parallel_mergejoin (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra, Path *inner_cheapest_total)
 
static void hash_inner_and_outer (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
 
static Listselect_mergejoin_clauses (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, List *restrictlist, JoinType jointype, bool *mergejoin_allowed)
 
static void generate_mergejoin_paths (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *innerrel, Path *outerpath, JoinType jointype, JoinPathExtraData *extra, bool useallclauses, Path *inner_cheapest_total, List *merge_pathkeys, bool is_partial)
 
void add_paths_to_joinrel (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, SpecialJoinInfo *sjinfo, List *restrictlist)
 
static bool allow_star_schema_join (PlannerInfo *root, Relids outerrelids, Relids inner_paramrels)
 
static void try_nestloop_path (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, JoinType jointype, JoinPathExtraData *extra)
 
static void try_partial_nestloop_path (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, JoinType jointype, JoinPathExtraData *extra)
 
static void try_mergejoin_path (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, List *mergeclauses, List *outersortkeys, List *innersortkeys, JoinType jointype, JoinPathExtraData *extra, bool is_partial)
 
static void try_hashjoin_path (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *hashclauses, JoinType jointype, JoinPathExtraData *extra)
 
static void try_partial_hashjoin_path (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *hashclauses, JoinType jointype, JoinPathExtraData *extra)
 
static bool clause_sides_match_join (RestrictInfo *rinfo, RelOptInfo *outerrel, RelOptInfo *innerrel)
 

Variables

set_join_pathlist_hook_type set_join_pathlist_hook = NULL
 

Macro Definition Documentation

◆ PATH_PARAM_BY_PARENT

#define PATH_PARAM_BY_PARENT (   path,
  rel 
)
Value:
((path)->param_info && bms_overlap(PATH_REQ_OUTER(path), \
(rel)->top_parent_relids))
#define PATH_REQ_OUTER(path)
Definition: relation.h:1061
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443

Definition at line 33 of file joinpath.c.

Referenced by try_nestloop_path(), and try_partial_nestloop_path().

◆ PATH_PARAM_BY_REL

#define PATH_PARAM_BY_REL (   path,
  rel 
)    (PATH_PARAM_BY_REL_SELF(path, rel) || PATH_PARAM_BY_PARENT(path, rel))

Definition at line 39 of file joinpath.c.

Referenced by hash_inner_and_outer(), match_unsorted_outer(), and sort_inner_and_outer().

◆ PATH_PARAM_BY_REL_SELF

#define PATH_PARAM_BY_REL_SELF (   path,
  rel 
)    ((path)->param_info && bms_overlap(PATH_REQ_OUTER(path), (rel)->relids))

Definition at line 36 of file joinpath.c.

Function Documentation

◆ add_paths_to_joinrel()

void add_paths_to_joinrel ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outerrel,
RelOptInfo innerrel,
JoinType  jointype,
SpecialJoinInfo sjinfo,
List restrictlist 
)

Definition at line 117 of file joinpath.c.

References PlannerInfo::all_baserels, bms_add_members(), bms_difference(), bms_is_subset(), bms_join(), bms_overlap(), compute_semi_anti_join_factors(), enable_hashjoin, enable_mergejoin, RelOptInfo::fdwroutine, FdwRoutine::GetForeignJoinPaths, hash_inner_and_outer(), JoinPathExtraData::inner_unique, innerrel_is_unique(), JOIN_ANTI, JOIN_FULL, PlannerInfo::join_info_list, JOIN_INNER, JOIN_SEMI, JOIN_UNIQUE_INNER, JOIN_UNIQUE_OUTER, SpecialJoinInfo::jointype, RelOptInfo::lateral_relids, lfirst, match_unsorted_outer(), JoinPathExtraData::mergeclause_list, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, NIL, JoinPathExtraData::param_source_rels, RelOptInfo::relids, RELOPT_OTHER_JOINREL, RelOptInfo::reloptkind, JoinPathExtraData::restrictlist, select_mergejoin_clauses(), JoinPathExtraData::semifactors, set_join_pathlist_hook, JoinPathExtraData::sjinfo, sort_inner_and_outer(), and RelOptInfo::top_parent_relids.

Referenced by populate_joinrel_with_paths().

124 {
125  JoinPathExtraData extra;
126  bool mergejoin_allowed = true;
127  ListCell *lc;
128  Relids joinrelids;
129 
130  /*
131  * PlannerInfo doesn't contain the SpecialJoinInfos created for joins
132  * between child relations, even if there is a SpecialJoinInfo node for
133  * the join between the topmost parents. So, while calculating Relids set
134  * representing the restriction, consider relids of topmost parent of
135  * partitions.
136  */
137  if (joinrel->reloptkind == RELOPT_OTHER_JOINREL)
138  joinrelids = joinrel->top_parent_relids;
139  else
140  joinrelids = joinrel->relids;
141 
142  extra.restrictlist = restrictlist;
143  extra.mergeclause_list = NIL;
144  extra.sjinfo = sjinfo;
145  extra.param_source_rels = NULL;
146 
147  /*
148  * See if the inner relation is provably unique for this outer rel.
149  *
150  * We have some special cases: for JOIN_SEMI and JOIN_ANTI, it doesn't
151  * matter since the executor can make the equivalent optimization anyway;
152  * we need not expend planner cycles on proofs. For JOIN_UNIQUE_INNER, we
153  * must be considering a semijoin whose inner side is not provably unique
154  * (else reduce_unique_semijoins would've simplified it), so there's no
155  * point in calling innerrel_is_unique. However, if the LHS covers all of
156  * the semijoin's min_lefthand, then it's appropriate to set inner_unique
157  * because the path produced by create_unique_path will be unique relative
158  * to the LHS. (If we have an LHS that's only part of the min_lefthand,
159  * that is *not* true.) For JOIN_UNIQUE_OUTER, pass JOIN_INNER to avoid
160  * letting that value escape this module.
161  */
162  switch (jointype)
163  {
164  case JOIN_SEMI:
165  case JOIN_ANTI:
166  extra.inner_unique = false; /* well, unproven */
167  break;
168  case JOIN_UNIQUE_INNER:
169  extra.inner_unique = bms_is_subset(sjinfo->min_lefthand,
170  outerrel->relids);
171  break;
172  case JOIN_UNIQUE_OUTER:
173  extra.inner_unique = innerrel_is_unique(root,
174  outerrel->relids,
175  innerrel,
176  JOIN_INNER,
177  restrictlist,
178  false);
179  break;
180  default:
181  extra.inner_unique = innerrel_is_unique(root,
182  outerrel->relids,
183  innerrel,
184  jointype,
185  restrictlist,
186  false);
187  break;
188  }
189 
190  /*
191  * Find potential mergejoin clauses. We can skip this if we are not
192  * interested in doing a mergejoin. However, mergejoin may be our only
193  * way of implementing a full outer join, so override enable_mergejoin if
194  * it's a full join.
195  */
196  if (enable_mergejoin || jointype == JOIN_FULL)
198  joinrel,
199  outerrel,
200  innerrel,
201  restrictlist,
202  jointype,
203  &mergejoin_allowed);
204 
205  /*
206  * If it's SEMI, ANTI, or inner_unique join, compute correction factors
207  * for cost estimation. These will be the same for all paths.
208  */
209  if (jointype == JOIN_SEMI || jointype == JOIN_ANTI || extra.inner_unique)
210  compute_semi_anti_join_factors(root, outerrel, innerrel,
211  jointype, sjinfo, restrictlist,
212  &extra.semifactors);
213 
214  /*
215  * Decide whether it's sensible to generate parameterized paths for this
216  * joinrel, and if so, which relations such paths should require. There
217  * is usually no need to create a parameterized result path unless there
218  * is a join order restriction that prevents joining one of our input rels
219  * directly to the parameter source rel instead of joining to the other
220  * input rel. (But see allow_star_schema_join().) This restriction
221  * reduces the number of parameterized paths we have to deal with at
222  * higher join levels, without compromising the quality of the resulting
223  * plan. We express the restriction as a Relids set that must overlap the
224  * parameterization of any proposed join path.
225  */
226  foreach(lc, root->join_info_list)
227  {
228  SpecialJoinInfo *sjinfo2 = (SpecialJoinInfo *) lfirst(lc);
229 
230  /*
231  * SJ is relevant to this join if we have some part of its RHS
232  * (possibly not all of it), and haven't yet joined to its LHS. (This
233  * test is pretty simplistic, but should be sufficient considering the
234  * join has already been proven legal.) If the SJ is relevant, it
235  * presents constraints for joining to anything not in its RHS.
236  */
237  if (bms_overlap(joinrelids, sjinfo2->min_righthand) &&
238  !bms_overlap(joinrelids, sjinfo2->min_lefthand))
241  sjinfo2->min_righthand));
242 
243  /* full joins constrain both sides symmetrically */
244  if (sjinfo2->jointype == JOIN_FULL &&
245  bms_overlap(joinrelids, sjinfo2->min_lefthand) &&
246  !bms_overlap(joinrelids, sjinfo2->min_righthand))
249  sjinfo2->min_lefthand));
250  }
251 
252  /*
253  * However, when a LATERAL subquery is involved, there will simply not be
254  * any paths for the joinrel that aren't parameterized by whatever the
255  * subquery is parameterized by, unless its parameterization is resolved
256  * within the joinrel. So we might as well allow additional dependencies
257  * on whatever residual lateral dependencies the joinrel will have.
258  */
260  joinrel->lateral_relids);
261 
262  /*
263  * 1. Consider mergejoin paths where both relations must be explicitly
264  * sorted. Skip this if we can't mergejoin.
265  */
266  if (mergejoin_allowed)
267  sort_inner_and_outer(root, joinrel, outerrel, innerrel,
268  jointype, &extra);
269 
270  /*
271  * 2. Consider paths where the outer relation need not be explicitly
272  * sorted. This includes both nestloops and mergejoins where the outer
273  * path is already ordered. Again, skip this if we can't mergejoin.
274  * (That's okay because we know that nestloop can't handle right/full
275  * joins at all, so it wouldn't work in the prohibited cases either.)
276  */
277  if (mergejoin_allowed)
278  match_unsorted_outer(root, joinrel, outerrel, innerrel,
279  jointype, &extra);
280 
281 #ifdef NOT_USED
282 
283  /*
284  * 3. Consider paths where the inner relation need not be explicitly
285  * sorted. This includes mergejoins only (nestloops were already built in
286  * match_unsorted_outer).
287  *
288  * Diked out as redundant 2/13/2000 -- tgl. There isn't any really
289  * significant difference between the inner and outer side of a mergejoin,
290  * so match_unsorted_inner creates no paths that aren't equivalent to
291  * those made by match_unsorted_outer when add_paths_to_joinrel() is
292  * invoked with the two rels given in the other order.
293  */
294  if (mergejoin_allowed)
295  match_unsorted_inner(root, joinrel, outerrel, innerrel,
296  jointype, &extra);
297 #endif
298 
299  /*
300  * 4. Consider paths where both outer and inner relations must be hashed
301  * before being joined. As above, disregard enable_hashjoin for full
302  * joins, because there may be no other alternative.
303  */
304  if (enable_hashjoin || jointype == JOIN_FULL)
305  hash_inner_and_outer(root, joinrel, outerrel, innerrel,
306  jointype, &extra);
307 
308  /*
309  * 5. If inner and outer relations are foreign tables (or joins) belonging
310  * to the same server and assigned to the same user to check access
311  * permissions as, give the FDW a chance to push down joins.
312  */
313  if (joinrel->fdwroutine &&
315  joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
316  outerrel, innerrel,
317  jointype, &extra);
318 
319  /*
320  * 6. Finally, give extensions a chance to manipulate the path list.
321  */
323  set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
324  jointype, &extra);
325 }
#define NIL
Definition: pg_list.h:69
SemiAntiJoinFactors semifactors
Definition: relation.h:2274
RelOptKind reloptkind
Definition: relation.h:582
List * join_info_list
Definition: relation.h:250
Relids min_righthand
Definition: relation.h:2008
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:284
static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:1670
Relids lateral_relids
Definition: relation.h:610
SpecialJoinInfo * sjinfo
Definition: relation.h:2273
static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:872
Relids all_baserels
Definition: relation.h:196
GetForeignJoinPaths_function GetForeignJoinPaths
Definition: fdwapi.h:194
Relids param_source_rels
Definition: relation.h:2275
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:838
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
struct FdwRoutine * fdwroutine
Definition: relation.h:636
List * mergeclause_list
Definition: relation.h:2271
Relids relids
Definition: relation.h:585
bool innerrel_is_unique(PlannerInfo *root, Relids outerrelids, RelOptInfo *innerrel, JoinType jointype, List *restrictlist, bool force_cache)
Definition: analyzejoins.c:970
static List * select_mergejoin_clauses(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, List *restrictlist, JoinType jointype, bool *mergejoin_allowed)
Definition: joinpath.c:1901
List * restrictlist
Definition: relation.h:2270
set_join_pathlist_hook_type set_join_pathlist_hook
Definition: joinpath.c:27
bool enable_mergejoin
Definition: costsize.c:127
#define lfirst(lc)
Definition: pg_list.h:106
void compute_semi_anti_join_factors(PlannerInfo *root, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, SpecialJoinInfo *sjinfo, List *restrictlist, SemiAntiJoinFactors *semifactors)
Definition: costsize.c:3828
JoinType jointype
Definition: relation.h:2011
bool enable_hashjoin
Definition: costsize.c:128
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
Relids min_lefthand
Definition: relation.h:2007
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:755
Relids top_parent_relids
Definition: relation.h:654
static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:1324

◆ allow_star_schema_join()

static bool allow_star_schema_join ( PlannerInfo root,
Relids  outerrelids,
Relids  inner_paramrels 
)
inlinestatic

Definition at line 343 of file joinpath.c.

References bms_nonempty_difference(), and bms_overlap().

Referenced by try_nestloop_path().

346 {
347  /*
348  * It's a star-schema case if the outer rel provides some but not all of
349  * the inner rel's parameterization.
350  */
351  return (bms_overlap(inner_paramrels, outerrelids) &&
352  bms_nonempty_difference(inner_paramrels, outerrelids));
353 }
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494

◆ clause_sides_match_join()

static bool clause_sides_match_join ( RestrictInfo rinfo,
RelOptInfo outerrel,
RelOptInfo innerrel 
)
inlinestatic

Definition at line 840 of file joinpath.c.

References bms_is_subset(), RestrictInfo::left_relids, RestrictInfo::outer_is_left, RelOptInfo::relids, and RestrictInfo::right_relids.

Referenced by hash_inner_and_outer(), and select_mergejoin_clauses().

842 {
843  if (bms_is_subset(rinfo->left_relids, outerrel->relids) &&
844  bms_is_subset(rinfo->right_relids, innerrel->relids))
845  {
846  /* lefthand side is outer */
847  rinfo->outer_is_left = true;
848  return true;
849  }
850  else if (bms_is_subset(rinfo->left_relids, innerrel->relids) &&
851  bms_is_subset(rinfo->right_relids, outerrel->relids))
852  {
853  /* righthand side is outer */
854  rinfo->outer_is_left = false;
855  return true;
856  }
857  return false; /* no good for these input relations */
858 }
Relids left_relids
Definition: relation.h:1862
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
bool outer_is_left
Definition: relation.h:1890
Relids relids
Definition: relation.h:585
Relids right_relids
Definition: relation.h:1863

◆ consider_parallel_mergejoin()

static void consider_parallel_mergejoin ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outerrel,
RelOptInfo innerrel,
JoinType  jointype,
JoinPathExtraData extra,
Path inner_cheapest_total 
)
static

Definition at line 1558 of file joinpath.c.

References build_join_pathkeys(), generate_mergejoin_paths(), lfirst, RelOptInfo::partial_pathlist, and Path::pathkeys.

Referenced by match_unsorted_outer().

1565 {
1566  ListCell *lc1;
1567 
1568  /* generate merge join path for each partial outer path */
1569  foreach(lc1, outerrel->partial_pathlist)
1570  {
1571  Path *outerpath = (Path *) lfirst(lc1);
1572  List *merge_pathkeys;
1573 
1574  /*
1575  * Figure out what useful ordering any paths we create will have.
1576  */
1577  merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
1578  outerpath->pathkeys);
1579 
1580  generate_mergejoin_paths(root, joinrel, innerrel, outerpath, jointype,
1581  extra, false, inner_cheapest_total,
1582  merge_pathkeys, true);
1583  }
1584 }
List * partial_pathlist
Definition: relation.h:601
List * build_join_pathkeys(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, List *outer_pathkeys)
Definition: pathkeys.c:822
static void generate_mergejoin_paths(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *innerrel, Path *outerpath, JoinType jointype, JoinPathExtraData *extra, bool useallclauses, Path *inner_cheapest_total, List *merge_pathkeys, bool is_partial)
Definition: joinpath.c:1074
List * pathkeys
Definition: relation.h:1056
#define lfirst(lc)
Definition: pg_list.h:106
Definition: pg_list.h:45

◆ consider_parallel_nestloop()

static void consider_parallel_nestloop ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outerrel,
RelOptInfo innerrel,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 1598 of file joinpath.c.

References Assert, build_join_pathkeys(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_total_path, create_unique_path(), JOIN_INNER, JOIN_UNIQUE_INNER, lfirst, Path::parallel_safe, RelOptInfo::partial_pathlist, Path::pathkeys, JoinPathExtraData::sjinfo, and try_partial_nestloop_path().

Referenced by match_unsorted_outer().

1604 {
1605  JoinType save_jointype = jointype;
1606  ListCell *lc1;
1607 
1608  if (jointype == JOIN_UNIQUE_INNER)
1609  jointype = JOIN_INNER;
1610 
1611  foreach(lc1, outerrel->partial_pathlist)
1612  {
1613  Path *outerpath = (Path *) lfirst(lc1);
1614  List *pathkeys;
1615  ListCell *lc2;
1616 
1617  /* Figure out what useful ordering any paths we create will have. */
1618  pathkeys = build_join_pathkeys(root, joinrel, jointype,
1619  outerpath->pathkeys);
1620 
1621  /*
1622  * Try the cheapest parameterized paths; only those which will produce
1623  * an unparameterized path when joined to this outerrel will survive
1624  * try_partial_nestloop_path. The cheapest unparameterized path is
1625  * also in this list.
1626  */
1627  foreach(lc2, innerrel->cheapest_parameterized_paths)
1628  {
1629  Path *innerpath = (Path *) lfirst(lc2);
1630 
1631  /* Can't join to an inner path that is not parallel-safe */
1632  if (!innerpath->parallel_safe)
1633  continue;
1634 
1635  /*
1636  * If we're doing JOIN_UNIQUE_INNER, we can only use the inner's
1637  * cheapest_total_path, and we have to unique-ify it. (We might
1638  * be able to relax this to allow other safe, unparameterized
1639  * inner paths, but right now create_unique_path is not on board
1640  * with that.)
1641  */
1642  if (save_jointype == JOIN_UNIQUE_INNER)
1643  {
1644  if (innerpath != innerrel->cheapest_total_path)
1645  continue;
1646  innerpath = (Path *) create_unique_path(root, innerrel,
1647  innerpath,
1648  extra->sjinfo);
1649  Assert(innerpath);
1650  }
1651 
1652  try_partial_nestloop_path(root, joinrel, outerpath, innerpath,
1653  pathkeys, jointype, extra);
1654  }
1655  }
1656 }
List * partial_pathlist
Definition: relation.h:601
List * cheapest_parameterized_paths
Definition: relation.h:605
UniquePath * create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, SpecialJoinInfo *sjinfo)
Definition: pathnode.c:1440
List * build_join_pathkeys(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, List *outer_pathkeys)
Definition: pathkeys.c:822
JoinType
Definition: nodes.h:674
SpecialJoinInfo * sjinfo
Definition: relation.h:2273
struct Path * cheapest_total_path
Definition: relation.h:603
static void try_partial_nestloop_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:473
List * pathkeys
Definition: relation.h:1056
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
bool parallel_safe
Definition: relation.h:1048
Definition: pg_list.h:45

◆ generate_mergejoin_paths()

static void generate_mergejoin_paths ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo innerrel,
Path outerpath,
JoinType  jointype,
JoinPathExtraData extra,
bool  useallclauses,
Path inner_cheapest_total,
List merge_pathkeys,
bool  is_partial 
)
static

Definition at line 1074 of file joinpath.c.

References Assert, compare_path_costs(), find_mergeclauses_for_pathkeys(), get_cheapest_path_for_pathkeys(), JOIN_FULL, JOIN_INNER, JOIN_UNIQUE_INNER, JOIN_UNIQUE_OUTER, list_copy(), list_length(), list_truncate(), make_inner_pathkeys_for_merge(), JoinPathExtraData::mergeclause_list, NIL, Path::pathkeys, pathkeys_contained_in(), RelOptInfo::pathlist, STARTUP_COST, TOTAL_COST, and try_mergejoin_path().

Referenced by consider_parallel_mergejoin(), and match_unsorted_outer().

1084 {
1085  List *mergeclauses;
1086  List *innersortkeys;
1087  List *trialsortkeys;
1088  Path *cheapest_startup_inner;
1089  Path *cheapest_total_inner;
1090  JoinType save_jointype = jointype;
1091  int num_sortkeys;
1092  int sortkeycnt;
1093 
1094  if (jointype == JOIN_UNIQUE_OUTER || jointype == JOIN_UNIQUE_INNER)
1095  jointype = JOIN_INNER;
1096 
1097  /* Look for useful mergeclauses (if any) */
1098  mergeclauses = find_mergeclauses_for_pathkeys(root,
1099  outerpath->pathkeys,
1100  true,
1101  extra->mergeclause_list);
1102 
1103  /*
1104  * Done with this outer path if no chance for a mergejoin.
1105  *
1106  * Special corner case: for "x FULL JOIN y ON true", there will be no join
1107  * clauses at all. Ordinarily we'd generate a clauseless nestloop path,
1108  * but since mergejoin is our only join type that supports FULL JOIN
1109  * without any join clauses, it's necessary to generate a clauseless
1110  * mergejoin path instead.
1111  */
1112  if (mergeclauses == NIL)
1113  {
1114  if (jointype == JOIN_FULL)
1115  /* okay to try for mergejoin */ ;
1116  else
1117  return;
1118  }
1119  if (useallclauses &&
1120  list_length(mergeclauses) != list_length(extra->mergeclause_list))
1121  return;
1122 
1123  /* Compute the required ordering of the inner path */
1124  innersortkeys = make_inner_pathkeys_for_merge(root,
1125  mergeclauses,
1126  outerpath->pathkeys);
1127 
1128  /*
1129  * Generate a mergejoin on the basis of sorting the cheapest inner. Since
1130  * a sort will be needed, only cheapest total cost matters. (But
1131  * try_mergejoin_path will do the right thing if inner_cheapest_total is
1132  * already correctly sorted.)
1133  */
1134  try_mergejoin_path(root,
1135  joinrel,
1136  outerpath,
1137  inner_cheapest_total,
1138  merge_pathkeys,
1139  mergeclauses,
1140  NIL,
1141  innersortkeys,
1142  jointype,
1143  extra,
1144  is_partial);
1145 
1146  /* Can't do anything else if inner path needs to be unique'd */
1147  if (save_jointype == JOIN_UNIQUE_INNER)
1148  return;
1149 
1150  /*
1151  * Look for presorted inner paths that satisfy the innersortkey list ---
1152  * or any truncation thereof, if we are allowed to build a mergejoin using
1153  * a subset of the merge clauses. Here, we consider both cheap startup
1154  * cost and cheap total cost.
1155  *
1156  * Currently we do not consider parameterized inner paths here. This
1157  * interacts with decisions elsewhere that also discriminate against
1158  * mergejoins with parameterized inputs; see comments in
1159  * src/backend/optimizer/README.
1160  *
1161  * As we shorten the sortkey list, we should consider only paths that are
1162  * strictly cheaper than (in particular, not the same as) any path found
1163  * in an earlier iteration. Otherwise we'd be intentionally using fewer
1164  * merge keys than a given path allows (treating the rest as plain
1165  * joinquals), which is unlikely to be a good idea. Also, eliminating
1166  * paths here on the basis of compare_path_costs is a lot cheaper than
1167  * building the mergejoin path only to throw it away.
1168  *
1169  * If inner_cheapest_total is well enough sorted to have not required a
1170  * sort in the path made above, we shouldn't make a duplicate path with
1171  * it, either. We handle that case with the same logic that handles the
1172  * previous consideration, by initializing the variables that track
1173  * cheapest-so-far properly. Note that we do NOT reject
1174  * inner_cheapest_total if we find it matches some shorter set of
1175  * pathkeys. That case corresponds to using fewer mergekeys to avoid
1176  * sorting inner_cheapest_total, whereas we did sort it above, so the
1177  * plans being considered are different.
1178  */
1179  if (pathkeys_contained_in(innersortkeys,
1180  inner_cheapest_total->pathkeys))
1181  {
1182  /* inner_cheapest_total didn't require a sort */
1183  cheapest_startup_inner = inner_cheapest_total;
1184  cheapest_total_inner = inner_cheapest_total;
1185  }
1186  else
1187  {
1188  /* it did require a sort, at least for the full set of keys */
1189  cheapest_startup_inner = NULL;
1190  cheapest_total_inner = NULL;
1191  }
1192  num_sortkeys = list_length(innersortkeys);
1193  if (num_sortkeys > 1 && !useallclauses)
1194  trialsortkeys = list_copy(innersortkeys); /* need modifiable copy */
1195  else
1196  trialsortkeys = innersortkeys; /* won't really truncate */
1197 
1198  for (sortkeycnt = num_sortkeys; sortkeycnt > 0; sortkeycnt--)
1199  {
1200  Path *innerpath;
1201  List *newclauses = NIL;
1202 
1203  /*
1204  * Look for an inner path ordered well enough for the first
1205  * 'sortkeycnt' innersortkeys. NB: trialsortkeys list is modified
1206  * destructively, which is why we made a copy...
1207  */
1208  trialsortkeys = list_truncate(trialsortkeys, sortkeycnt);
1209  innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,
1210  trialsortkeys,
1211  NULL,
1212  TOTAL_COST,
1213  is_partial);
1214  if (innerpath != NULL &&
1215  (cheapest_total_inner == NULL ||
1216  compare_path_costs(innerpath, cheapest_total_inner,
1217  TOTAL_COST) < 0))
1218  {
1219  /* Found a cheap (or even-cheaper) sorted path */
1220  /* Select the right mergeclauses, if we didn't already */
1221  if (sortkeycnt < num_sortkeys)
1222  {
1223  newclauses =
1225  trialsortkeys,
1226  false,
1227  mergeclauses);
1228  Assert(newclauses != NIL);
1229  }
1230  else
1231  newclauses = mergeclauses;
1232  try_mergejoin_path(root,
1233  joinrel,
1234  outerpath,
1235  innerpath,
1236  merge_pathkeys,
1237  newclauses,
1238  NIL,
1239  NIL,
1240  jointype,
1241  extra,
1242  is_partial);
1243  cheapest_total_inner = innerpath;
1244  }
1245  /* Same on the basis of cheapest startup cost ... */
1246  innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,
1247  trialsortkeys,
1248  NULL,
1249  STARTUP_COST,
1250  is_partial);
1251  if (innerpath != NULL &&
1252  (cheapest_startup_inner == NULL ||
1253  compare_path_costs(innerpath, cheapest_startup_inner,
1254  STARTUP_COST) < 0))
1255  {
1256  /* Found a cheap (or even-cheaper) sorted path */
1257  if (innerpath != cheapest_total_inner)
1258  {
1259  /*
1260  * Avoid rebuilding clause list if we already made one; saves
1261  * memory in big join trees...
1262  */
1263  if (newclauses == NIL)
1264  {
1265  if (sortkeycnt < num_sortkeys)
1266  {
1267  newclauses =
1269  trialsortkeys,
1270  false,
1271  mergeclauses);
1272  Assert(newclauses != NIL);
1273  }
1274  else
1275  newclauses = mergeclauses;
1276  }
1277  try_mergejoin_path(root,
1278  joinrel,
1279  outerpath,
1280  innerpath,
1281  merge_pathkeys,
1282  newclauses,
1283  NIL,
1284  NIL,
1285  jointype,
1286  extra,
1287  is_partial);
1288  }
1289  cheapest_startup_inner = innerpath;
1290  }
1291 
1292  /*
1293  * Don't consider truncated sortkeys if we need all clauses.
1294  */
1295  if (useallclauses)
1296  break;
1297  }
1298 }
Path * get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, Relids required_outer, CostSelector cost_criterion, bool require_parallel_safe)
Definition: pathkeys.c:343
static void try_mergejoin_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, List *mergeclauses, List *outersortkeys, List *innersortkeys, JoinType jointype, JoinPathExtraData *extra, bool is_partial)
Definition: joinpath.c:555
#define NIL
Definition: pg_list.h:69
List * list_truncate(List *list, int new_size)
Definition: list.c:350
List * list_copy(const List *oldlist)
Definition: list.c:1160
List * make_inner_pathkeys_for_merge(PlannerInfo *root, List *mergeclauses, List *outer_pathkeys)
Definition: pathkeys.c:1292
JoinType
Definition: nodes.h:674
int compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
Definition: pathnode.c:69
List * mergeclause_list
Definition: relation.h:2271
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition: pathkeys.c:317
List * pathkeys
Definition: relation.h:1056
#define Assert(condition)
Definition: c.h:670
static int list_length(const List *l)
Definition: pg_list.h:89
List * find_mergeclauses_for_pathkeys(PlannerInfo *root, List *pathkeys, bool outer_keys, List *restrictinfos)
Definition: pathkeys.c:1003
List * pathlist
Definition: relation.h:599
Definition: pg_list.h:45

◆ hash_inner_and_outer()

static void hash_inner_and_outer ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outerrel,
RelOptInfo innerrel,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 1670 of file joinpath.c.

References Assert, bms_is_empty(), RestrictInfo::can_join, RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, clause_sides_match_join(), RelOptInfo::consider_parallel, create_unique_path(), get_cheapest_parallel_safe_total_inner(), RestrictInfo::hashjoinoperator, InvalidOid, IS_OUTER_JOIN, RestrictInfo::is_pushed_down, JOIN_FULL, JOIN_INNER, JOIN_RIGHT, JOIN_UNIQUE_INNER, JOIN_UNIQUE_OUTER, lappend(), RelOptInfo::lateral_relids, lfirst, linitial, NIL, Path::parallel_safe, RelOptInfo::partial_pathlist, PATH_PARAM_BY_REL, RelOptInfo::pathlist, JoinPathExtraData::restrictlist, JoinPathExtraData::sjinfo, try_hashjoin_path(), and try_partial_hashjoin_path().

Referenced by add_paths_to_joinrel().

1676 {
1677  JoinType save_jointype = jointype;
1678  bool isouterjoin = IS_OUTER_JOIN(jointype);
1679  List *hashclauses;
1680  ListCell *l;
1681 
1682  /*
1683  * We need to build only one hashclauses list for any given pair of outer
1684  * and inner relations; all of the hashable clauses will be used as keys.
1685  *
1686  * Scan the join's restrictinfo list to find hashjoinable clauses that are
1687  * usable with this pair of sub-relations.
1688  */
1689  hashclauses = NIL;
1690  foreach(l, extra->restrictlist)
1691  {
1692  RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
1693 
1694  /*
1695  * If processing an outer join, only use its own join clauses for
1696  * hashing. For inner joins we need not be so picky.
1697  */
1698  if (isouterjoin && restrictinfo->is_pushed_down)
1699  continue;
1700 
1701  if (!restrictinfo->can_join ||
1702  restrictinfo->hashjoinoperator == InvalidOid)
1703  continue; /* not hashjoinable */
1704 
1705  /*
1706  * Check if clause has the form "outer op inner" or "inner op outer".
1707  */
1708  if (!clause_sides_match_join(restrictinfo, outerrel, innerrel))
1709  continue; /* no good for these input relations */
1710 
1711  hashclauses = lappend(hashclauses, restrictinfo);
1712  }
1713 
1714  /* If we found any usable hashclauses, make paths */
1715  if (hashclauses)
1716  {
1717  /*
1718  * We consider both the cheapest-total-cost and cheapest-startup-cost
1719  * outer paths. There's no need to consider any but the
1720  * cheapest-total-cost inner path, however.
1721  */
1722  Path *cheapest_startup_outer = outerrel->cheapest_startup_path;
1723  Path *cheapest_total_outer = outerrel->cheapest_total_path;
1724  Path *cheapest_total_inner = innerrel->cheapest_total_path;
1725 
1726  /*
1727  * If either cheapest-total path is parameterized by the other rel, we
1728  * can't use a hashjoin. (There's no use looking for alternative
1729  * input paths, since these should already be the least-parameterized
1730  * available paths.)
1731  */
1732  if (PATH_PARAM_BY_REL(cheapest_total_outer, innerrel) ||
1733  PATH_PARAM_BY_REL(cheapest_total_inner, outerrel))
1734  return;
1735 
1736  /* Unique-ify if need be; we ignore parameterized possibilities */
1737  if (jointype == JOIN_UNIQUE_OUTER)
1738  {
1739  cheapest_total_outer = (Path *)
1740  create_unique_path(root, outerrel,
1741  cheapest_total_outer, extra->sjinfo);
1742  Assert(cheapest_total_outer);
1743  jointype = JOIN_INNER;
1744  try_hashjoin_path(root,
1745  joinrel,
1746  cheapest_total_outer,
1747  cheapest_total_inner,
1748  hashclauses,
1749  jointype,
1750  extra);
1751  /* no possibility of cheap startup here */
1752  }
1753  else if (jointype == JOIN_UNIQUE_INNER)
1754  {
1755  cheapest_total_inner = (Path *)
1756  create_unique_path(root, innerrel,
1757  cheapest_total_inner, extra->sjinfo);
1758  Assert(cheapest_total_inner);
1759  jointype = JOIN_INNER;
1760  try_hashjoin_path(root,
1761  joinrel,
1762  cheapest_total_outer,
1763  cheapest_total_inner,
1764  hashclauses,
1765  jointype,
1766  extra);
1767  if (cheapest_startup_outer != NULL &&
1768  cheapest_startup_outer != cheapest_total_outer)
1769  try_hashjoin_path(root,
1770  joinrel,
1771  cheapest_startup_outer,
1772  cheapest_total_inner,
1773  hashclauses,
1774  jointype,
1775  extra);
1776  }
1777  else
1778  {
1779  /*
1780  * For other jointypes, we consider the cheapest startup outer
1781  * together with the cheapest total inner, and then consider
1782  * pairings of cheapest-total paths including parameterized ones.
1783  * There is no use in generating parameterized paths on the basis
1784  * of possibly cheap startup cost, so this is sufficient.
1785  */
1786  ListCell *lc1;
1787  ListCell *lc2;
1788 
1789  if (cheapest_startup_outer != NULL)
1790  try_hashjoin_path(root,
1791  joinrel,
1792  cheapest_startup_outer,
1793  cheapest_total_inner,
1794  hashclauses,
1795  jointype,
1796  extra);
1797 
1798  foreach(lc1, outerrel->cheapest_parameterized_paths)
1799  {
1800  Path *outerpath = (Path *) lfirst(lc1);
1801 
1802  /*
1803  * We cannot use an outer path that is parameterized by the
1804  * inner rel.
1805  */
1806  if (PATH_PARAM_BY_REL(outerpath, innerrel))
1807  continue;
1808 
1809  foreach(lc2, innerrel->cheapest_parameterized_paths)
1810  {
1811  Path *innerpath = (Path *) lfirst(lc2);
1812 
1813  /*
1814  * We cannot use an inner path that is parameterized by
1815  * the outer rel, either.
1816  */
1817  if (PATH_PARAM_BY_REL(innerpath, outerrel))
1818  continue;
1819 
1820  if (outerpath == cheapest_startup_outer &&
1821  innerpath == cheapest_total_inner)
1822  continue; /* already tried it */
1823 
1824  try_hashjoin_path(root,
1825  joinrel,
1826  outerpath,
1827  innerpath,
1828  hashclauses,
1829  jointype,
1830  extra);
1831  }
1832  }
1833  }
1834 
1835  /*
1836  * If the joinrel is parallel-safe, we may be able to consider a
1837  * partial hash join. However, we can't handle JOIN_UNIQUE_OUTER,
1838  * because the outer path will be partial, and therefore we won't be
1839  * able to properly guarantee uniqueness. Similarly, we can't handle
1840  * JOIN_FULL and JOIN_RIGHT, because they can produce false null
1841  * extended rows. Also, the resulting path must not be parameterized.
1842  */
1843  if (joinrel->consider_parallel &&
1844  save_jointype != JOIN_UNIQUE_OUTER &&
1845  save_jointype != JOIN_FULL &&
1846  save_jointype != JOIN_RIGHT &&
1847  outerrel->partial_pathlist != NIL &&
1848  bms_is_empty(joinrel->lateral_relids))
1849  {
1850  Path *cheapest_partial_outer;
1851  Path *cheapest_safe_inner = NULL;
1852 
1853  cheapest_partial_outer =
1854  (Path *) linitial(outerrel->partial_pathlist);
1855 
1856  /*
1857  * Normally, given that the joinrel is parallel-safe, the cheapest
1858  * total inner path will also be parallel-safe, but if not, we'll
1859  * have to search for the cheapest safe, unparameterized inner
1860  * path. If doing JOIN_UNIQUE_INNER, we can't use any alternative
1861  * inner path.
1862  */
1863  if (cheapest_total_inner->parallel_safe)
1864  cheapest_safe_inner = cheapest_total_inner;
1865  else if (save_jointype != JOIN_UNIQUE_INNER)
1866  cheapest_safe_inner =
1868 
1869  if (cheapest_safe_inner != NULL)
1870  try_partial_hashjoin_path(root, joinrel,
1871  cheapest_partial_outer,
1872  cheapest_safe_inner,
1873  hashclauses, jointype, extra);
1874  }
1875  }
1876 }
#define NIL
Definition: pg_list.h:69
static void try_hashjoin_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *hashclauses, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:720
struct Path * cheapest_startup_path
Definition: relation.h:602
static void try_partial_hashjoin_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *hashclauses, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:781
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:723
List * partial_pathlist
Definition: relation.h:601
List * cheapest_parameterized_paths
Definition: relation.h:605
UniquePath * create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, SpecialJoinInfo *sjinfo)
Definition: pathnode.c:1440
JoinType
Definition: nodes.h:674
Relids lateral_relids
Definition: relation.h:610
SpecialJoinInfo * sjinfo
Definition: relation.h:2273
#define linitial(l)
Definition: pg_list.h:111
bool can_join
Definition: relation.h:1841
struct Path * cheapest_total_path
Definition: relation.h:603
Path * get_cheapest_parallel_safe_total_inner(List *paths)
Definition: pathkeys.c:421
List * lappend(List *list, void *datum)
Definition: list.c:128
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:663
List * restrictlist
Definition: relation.h:2270
#define InvalidOid
Definition: postgres_ext.h:36
bool is_pushed_down
Definition: relation.h:1837
#define PATH_PARAM_BY_REL(path, rel)
Definition: joinpath.c:39
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
bool parallel_safe
Definition: relation.h:1048
static bool clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel, RelOptInfo *innerrel)
Definition: joinpath.c:840
Oid hashjoinoperator
Definition: relation.h:1893
bool consider_parallel
Definition: relation.h:593
List * pathlist
Definition: relation.h:599
Definition: pg_list.h:45

◆ match_unsorted_outer()

static void match_unsorted_outer ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outerrel,
RelOptInfo innerrel,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 1324 of file joinpath.c.

References Assert, bms_is_empty(), build_join_pathkeys(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_total_path, RelOptInfo::consider_parallel, consider_parallel_mergejoin(), consider_parallel_nestloop(), create_material_path(), create_unique_path(), elog, enable_material, ERROR, ExecMaterializesOutput(), generate_mergejoin_paths(), get_cheapest_parallel_safe_total_inner(), JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, JOIN_SEMI, JOIN_UNIQUE_INNER, JOIN_UNIQUE_OUTER, RelOptInfo::lateral_relids, lfirst, NIL, Path::parallel_safe, RelOptInfo::partial_pathlist, PATH_PARAM_BY_REL, Path::pathkeys, RelOptInfo::pathlist, Path::pathtype, JoinPathExtraData::sjinfo, and try_nestloop_path().

Referenced by add_paths_to_joinrel().

1330 {
1331  JoinType save_jointype = jointype;
1332  bool nestjoinOK;
1333  bool useallclauses;
1334  Path *inner_cheapest_total = innerrel->cheapest_total_path;
1335  Path *matpath = NULL;
1336  ListCell *lc1;
1337 
1338  /*
1339  * Nestloop only supports inner, left, semi, and anti joins. Also, if we
1340  * are doing a right or full mergejoin, we must use *all* the mergeclauses
1341  * as join clauses, else we will not have a valid plan. (Although these
1342  * two flags are currently inverses, keep them separate for clarity and
1343  * possible future changes.)
1344  */
1345  switch (jointype)
1346  {
1347  case JOIN_INNER:
1348  case JOIN_LEFT:
1349  case JOIN_SEMI:
1350  case JOIN_ANTI:
1351  nestjoinOK = true;
1352  useallclauses = false;
1353  break;
1354  case JOIN_RIGHT:
1355  case JOIN_FULL:
1356  nestjoinOK = false;
1357  useallclauses = true;
1358  break;
1359  case JOIN_UNIQUE_OUTER:
1360  case JOIN_UNIQUE_INNER:
1361  jointype = JOIN_INNER;
1362  nestjoinOK = true;
1363  useallclauses = false;
1364  break;
1365  default:
1366  elog(ERROR, "unrecognized join type: %d",
1367  (int) jointype);
1368  nestjoinOK = false; /* keep compiler quiet */
1369  useallclauses = false;
1370  break;
1371  }
1372 
1373  /*
1374  * If inner_cheapest_total is parameterized by the outer rel, ignore it;
1375  * we will consider it below as a member of cheapest_parameterized_paths,
1376  * but the other possibilities considered in this routine aren't usable.
1377  */
1378  if (PATH_PARAM_BY_REL(inner_cheapest_total, outerrel))
1379  inner_cheapest_total = NULL;
1380 
1381  /*
1382  * If we need to unique-ify the inner path, we will consider only the
1383  * cheapest-total inner.
1384  */
1385  if (save_jointype == JOIN_UNIQUE_INNER)
1386  {
1387  /* No way to do this with an inner path parameterized by outer rel */
1388  if (inner_cheapest_total == NULL)
1389  return;
1390  inner_cheapest_total = (Path *)
1391  create_unique_path(root, innerrel, inner_cheapest_total, extra->sjinfo);
1392  Assert(inner_cheapest_total);
1393  }
1394  else if (nestjoinOK)
1395  {
1396  /*
1397  * Consider materializing the cheapest inner path, unless
1398  * enable_material is off or the path in question materializes its
1399  * output anyway.
1400  */
1401  if (enable_material && inner_cheapest_total != NULL &&
1402  !ExecMaterializesOutput(inner_cheapest_total->pathtype))
1403  matpath = (Path *)
1404  create_material_path(innerrel, inner_cheapest_total);
1405  }
1406 
1407  foreach(lc1, outerrel->pathlist)
1408  {
1409  Path *outerpath = (Path *) lfirst(lc1);
1410  List *merge_pathkeys;
1411 
1412  /*
1413  * We cannot use an outer path that is parameterized by the inner rel.
1414  */
1415  if (PATH_PARAM_BY_REL(outerpath, innerrel))
1416  continue;
1417 
1418  /*
1419  * If we need to unique-ify the outer path, it's pointless to consider
1420  * any but the cheapest outer. (XXX we don't consider parameterized
1421  * outers, nor inners, for unique-ified cases. Should we?)
1422  */
1423  if (save_jointype == JOIN_UNIQUE_OUTER)
1424  {
1425  if (outerpath != outerrel->cheapest_total_path)
1426  continue;
1427  outerpath = (Path *) create_unique_path(root, outerrel,
1428  outerpath, extra->sjinfo);
1429  Assert(outerpath);
1430  }
1431 
1432  /*
1433  * The result will have this sort order (even if it is implemented as
1434  * a nestloop, and even if some of the mergeclauses are implemented by
1435  * qpquals rather than as true mergeclauses):
1436  */
1437  merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
1438  outerpath->pathkeys);
1439 
1440  if (save_jointype == JOIN_UNIQUE_INNER)
1441  {
1442  /*
1443  * Consider nestloop join, but only with the unique-ified cheapest
1444  * inner path
1445  */
1446  try_nestloop_path(root,
1447  joinrel,
1448  outerpath,
1449  inner_cheapest_total,
1450  merge_pathkeys,
1451  jointype,
1452  extra);
1453  }
1454  else if (nestjoinOK)
1455  {
1456  /*
1457  * Consider nestloop joins using this outer path and various
1458  * available paths for the inner relation. We consider the
1459  * cheapest-total paths for each available parameterization of the
1460  * inner relation, including the unparameterized case.
1461  */
1462  ListCell *lc2;
1463 
1464  foreach(lc2, innerrel->cheapest_parameterized_paths)
1465  {
1466  Path *innerpath = (Path *) lfirst(lc2);
1467 
1468  try_nestloop_path(root,
1469  joinrel,
1470  outerpath,
1471  innerpath,
1472  merge_pathkeys,
1473  jointype,
1474  extra);
1475  }
1476 
1477  /* Also consider materialized form of the cheapest inner path */
1478  if (matpath != NULL)
1479  try_nestloop_path(root,
1480  joinrel,
1481  outerpath,
1482  matpath,
1483  merge_pathkeys,
1484  jointype,
1485  extra);
1486  }
1487 
1488  /* Can't do anything else if outer path needs to be unique'd */
1489  if (save_jointype == JOIN_UNIQUE_OUTER)
1490  continue;
1491 
1492  /* Can't do anything else if inner rel is parameterized by outer */
1493  if (inner_cheapest_total == NULL)
1494  continue;
1495 
1496  /* Generate merge join paths */
1497  generate_mergejoin_paths(root, joinrel, innerrel, outerpath,
1498  save_jointype, extra, useallclauses,
1499  inner_cheapest_total, merge_pathkeys,
1500  false);
1501  }
1502 
1503  /*
1504  * Consider partial nestloop and mergejoin plan if outerrel has any
1505  * partial path and the joinrel is parallel-safe. However, we can't
1506  * handle JOIN_UNIQUE_OUTER, because the outer path will be partial, and
1507  * therefore we won't be able to properly guarantee uniqueness. Nor can
1508  * we handle extra_lateral_rels, since partial paths must not be
1509  * parameterized. Similarly, we can't handle JOIN_FULL and JOIN_RIGHT,
1510  * because they can produce false null extended rows.
1511  */
1512  if (joinrel->consider_parallel &&
1513  save_jointype != JOIN_UNIQUE_OUTER &&
1514  save_jointype != JOIN_FULL &&
1515  save_jointype != JOIN_RIGHT &&
1516  outerrel->partial_pathlist != NIL &&
1517  bms_is_empty(joinrel->lateral_relids))
1518  {
1519  if (nestjoinOK)
1520  consider_parallel_nestloop(root, joinrel, outerrel, innerrel,
1521  save_jointype, extra);
1522 
1523  /*
1524  * If inner_cheapest_total is NULL or non parallel-safe then find the
1525  * cheapest total parallel safe path. If doing JOIN_UNIQUE_INNER, we
1526  * can't use any alternative inner path.
1527  */
1528  if (inner_cheapest_total == NULL ||
1529  !inner_cheapest_total->parallel_safe)
1530  {
1531  if (save_jointype == JOIN_UNIQUE_INNER)
1532  return;
1533 
1534  inner_cheapest_total = get_cheapest_parallel_safe_total_inner(
1535  innerrel->pathlist);
1536  }
1537 
1538  if (inner_cheapest_total)
1539  consider_parallel_mergejoin(root, joinrel, outerrel, innerrel,
1540  save_jointype, extra,
1541  inner_cheapest_total);
1542  }
1543 }
#define NIL
Definition: pg_list.h:69
static void try_nestloop_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:361
MaterialPath * create_material_path(RelOptInfo *rel, Path *subpath)
Definition: pathnode.c:1401
List * partial_pathlist
Definition: relation.h:601
List * cheapest_parameterized_paths
Definition: relation.h:605
UniquePath * create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, SpecialJoinInfo *sjinfo)
Definition: pathnode.c:1440
List * build_join_pathkeys(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, List *outer_pathkeys)
Definition: pathkeys.c:822
JoinType
Definition: nodes.h:674
NodeTag pathtype
Definition: relation.h:1040
Relids lateral_relids
Definition: relation.h:610
SpecialJoinInfo * sjinfo
Definition: relation.h:2273
#define ERROR
Definition: elog.h:43
struct Path * cheapest_total_path
Definition: relation.h:603
static void generate_mergejoin_paths(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *innerrel, Path *outerpath, JoinType jointype, JoinPathExtraData *extra, bool useallclauses, Path *inner_cheapest_total, List *merge_pathkeys, bool is_partial)
Definition: joinpath.c:1074
Path * get_cheapest_parallel_safe_total_inner(List *paths)
Definition: pathkeys.c:421
static void consider_parallel_nestloop(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:1598
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:663
static void consider_parallel_mergejoin(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, JoinType jointype, JoinPathExtraData *extra, Path *inner_cheapest_total)
Definition: joinpath.c:1558
#define PATH_PARAM_BY_REL(path, rel)
Definition: joinpath.c:39
List * pathkeys
Definition: relation.h:1056
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
bool parallel_safe
Definition: relation.h:1048
bool consider_parallel
Definition: relation.h:593
bool ExecMaterializesOutput(NodeTag plantype)
Definition: execAmi.c:577
List * pathlist
Definition: relation.h:599
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
bool enable_material
Definition: costsize.c:126

◆ select_mergejoin_clauses()

static List * select_mergejoin_clauses ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outerrel,
RelOptInfo innerrel,
List restrictlist,
JoinType  jointype,
bool mergejoin_allowed 
)
static

Definition at line 1901 of file joinpath.c.

References RestrictInfo::can_join, RestrictInfo::clause, clause_sides_match_join(), EC_MUST_BE_REDUNDANT, IS_OUTER_JOIN, RestrictInfo::is_pushed_down, IsA, JOIN_FULL, JOIN_RIGHT, lappend(), RestrictInfo::left_ec, lfirst, RestrictInfo::mergeopfamilies, NIL, RestrictInfo::right_ec, and update_mergeclause_eclasses().

Referenced by add_paths_to_joinrel().

1908 {
1909  List *result_list = NIL;
1910  bool isouterjoin = IS_OUTER_JOIN(jointype);
1911  bool have_nonmergeable_joinclause = false;
1912  ListCell *l;
1913 
1914  foreach(l, restrictlist)
1915  {
1916  RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
1917 
1918  /*
1919  * If processing an outer join, only use its own join clauses in the
1920  * merge. For inner joins we can use pushed-down clauses too. (Note:
1921  * we don't set have_nonmergeable_joinclause here because pushed-down
1922  * clauses will become otherquals not joinquals.)
1923  */
1924  if (isouterjoin && restrictinfo->is_pushed_down)
1925  continue;
1926 
1927  /* Check that clause is a mergeable operator clause */
1928  if (!restrictinfo->can_join ||
1929  restrictinfo->mergeopfamilies == NIL)
1930  {
1931  /*
1932  * The executor can handle extra joinquals that are constants, but
1933  * not anything else, when doing right/full merge join. (The
1934  * reason to support constants is so we can do FULL JOIN ON
1935  * FALSE.)
1936  */
1937  if (!restrictinfo->clause || !IsA(restrictinfo->clause, Const))
1938  have_nonmergeable_joinclause = true;
1939  continue; /* not mergejoinable */
1940  }
1941 
1942  /*
1943  * Check if clause has the form "outer op inner" or "inner op outer".
1944  */
1945  if (!clause_sides_match_join(restrictinfo, outerrel, innerrel))
1946  {
1947  have_nonmergeable_joinclause = true;
1948  continue; /* no good for these input relations */
1949  }
1950 
1951  /*
1952  * Insist that each side have a non-redundant eclass. This
1953  * restriction is needed because various bits of the planner expect
1954  * that each clause in a merge be associable with some pathkey in a
1955  * canonical pathkey list, but redundant eclasses can't appear in
1956  * canonical sort orderings. (XXX it might be worth relaxing this,
1957  * but not enough time to address it for 8.3.)
1958  *
1959  * Note: it would be bad if this condition failed for an otherwise
1960  * mergejoinable FULL JOIN clause, since that would result in
1961  * undesirable planner failure. I believe that is not possible
1962  * however; a variable involved in a full join could only appear in
1963  * below_outer_join eclasses, which aren't considered redundant.
1964  *
1965  * This case *can* happen for left/right join clauses: the outer-side
1966  * variable could be equated to a constant. Because we will propagate
1967  * that constant across the join clause, the loss of ability to do a
1968  * mergejoin is not really all that big a deal, and so it's not clear
1969  * that improving this is important.
1970  */
1971  update_mergeclause_eclasses(root, restrictinfo);
1972 
1973  if (EC_MUST_BE_REDUNDANT(restrictinfo->left_ec) ||
1974  EC_MUST_BE_REDUNDANT(restrictinfo->right_ec))
1975  {
1976  have_nonmergeable_joinclause = true;
1977  continue; /* can't handle redundant eclasses */
1978  }
1979 
1980  result_list = lappend(result_list, restrictinfo);
1981  }
1982 
1983  /*
1984  * Report whether mergejoin is allowed (see comment at top of function).
1985  */
1986  switch (jointype)
1987  {
1988  case JOIN_RIGHT:
1989  case JOIN_FULL:
1990  *mergejoin_allowed = !have_nonmergeable_joinclause;
1991  break;
1992  default:
1993  *mergejoin_allowed = true;
1994  break;
1995  }
1996 
1997  return result_list;
1998 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:723
EquivalenceClass * right_ec
Definition: relation.h:1884
List * mergeopfamilies
Definition: relation.h:1880
bool can_join
Definition: relation.h:1841
#define EC_MUST_BE_REDUNDANT(eclass)
Definition: relation.h:881
List * lappend(List *list, void *datum)
Definition: list.c:128
Expr * clause
Definition: relation.h:1835
bool is_pushed_down
Definition: relation.h:1837
#define lfirst(lc)
Definition: pg_list.h:106
static bool clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel, RelOptInfo *innerrel)
Definition: joinpath.c:840
EquivalenceClass * left_ec
Definition: relation.h:1883
Definition: pg_list.h:45
void update_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
Definition: pathkeys.c:968

◆ sort_inner_and_outer()

static void sort_inner_and_outer ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outerrel,
RelOptInfo innerrel,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 872 of file joinpath.c.

References Assert, bms_is_empty(), build_join_pathkeys(), RelOptInfo::cheapest_total_path, RelOptInfo::consider_parallel, create_unique_path(), find_mergeclauses_for_pathkeys(), get_cheapest_parallel_safe_total_inner(), JOIN_FULL, JOIN_INNER, JOIN_RIGHT, JOIN_UNIQUE_INNER, JOIN_UNIQUE_OUTER, RelOptInfo::lateral_relids, lcons(), lfirst, linitial, list_copy(), list_delete_ptr(), list_head(), list_length(), make_inner_pathkeys_for_merge(), JoinPathExtraData::mergeclause_list, NIL, Path::parallel_safe, RelOptInfo::partial_pathlist, PATH_PARAM_BY_REL, RelOptInfo::pathlist, select_outer_pathkeys_for_merge(), JoinPathExtraData::sjinfo, try_mergejoin_path(), and try_partial_mergejoin_path().

Referenced by add_paths_to_joinrel().

878 {
879  JoinType save_jointype = jointype;
880  Path *outer_path;
881  Path *inner_path;
882  Path *cheapest_partial_outer = NULL;
883  Path *cheapest_safe_inner = NULL;
884  List *all_pathkeys;
885  ListCell *l;
886 
887  /*
888  * We only consider the cheapest-total-cost input paths, since we are
889  * assuming here that a sort is required. We will consider
890  * cheapest-startup-cost input paths later, and only if they don't need a
891  * sort.
892  *
893  * This function intentionally does not consider parameterized input
894  * paths, except when the cheapest-total is parameterized. If we did so,
895  * we'd have a combinatorial explosion of mergejoin paths of dubious
896  * value. This interacts with decisions elsewhere that also discriminate
897  * against mergejoins with parameterized inputs; see comments in
898  * src/backend/optimizer/README.
899  */
900  outer_path = outerrel->cheapest_total_path;
901  inner_path = innerrel->cheapest_total_path;
902 
903  /*
904  * If either cheapest-total path is parameterized by the other rel, we
905  * can't use a mergejoin. (There's no use looking for alternative input
906  * paths, since these should already be the least-parameterized available
907  * paths.)
908  */
909  if (PATH_PARAM_BY_REL(outer_path, innerrel) ||
910  PATH_PARAM_BY_REL(inner_path, outerrel))
911  return;
912 
913  /*
914  * If unique-ification is requested, do it and then handle as a plain
915  * inner join.
916  */
917  if (jointype == JOIN_UNIQUE_OUTER)
918  {
919  outer_path = (Path *) create_unique_path(root, outerrel,
920  outer_path, extra->sjinfo);
921  Assert(outer_path);
922  jointype = JOIN_INNER;
923  }
924  else if (jointype == JOIN_UNIQUE_INNER)
925  {
926  inner_path = (Path *) create_unique_path(root, innerrel,
927  inner_path, extra->sjinfo);
928  Assert(inner_path);
929  jointype = JOIN_INNER;
930  }
931 
932  /*
933  * If the joinrel is parallel-safe, we may be able to consider a partial
934  * merge join. However, we can't handle JOIN_UNIQUE_OUTER, because the
935  * outer path will be partial, and therefore we won't be able to properly
936  * guarantee uniqueness. Similarly, we can't handle JOIN_FULL and
937  * JOIN_RIGHT, because they can produce false null extended rows. Also,
938  * the resulting path must not be parameterized.
939  */
940  if (joinrel->consider_parallel &&
941  save_jointype != JOIN_UNIQUE_OUTER &&
942  save_jointype != JOIN_FULL &&
943  save_jointype != JOIN_RIGHT &&
944  outerrel->partial_pathlist != NIL &&
945  bms_is_empty(joinrel->lateral_relids))
946  {
947  cheapest_partial_outer = (Path *) linitial(outerrel->partial_pathlist);
948 
949  if (inner_path->parallel_safe)
950  cheapest_safe_inner = inner_path;
951  else if (save_jointype != JOIN_UNIQUE_INNER)
952  cheapest_safe_inner =
954  }
955 
956  /*
957  * Each possible ordering of the available mergejoin clauses will generate
958  * a differently-sorted result path at essentially the same cost. We have
959  * no basis for choosing one over another at this level of joining, but
960  * some sort orders may be more useful than others for higher-level
961  * mergejoins, so it's worth considering multiple orderings.
962  *
963  * Actually, it's not quite true that every mergeclause ordering will
964  * generate a different path order, because some of the clauses may be
965  * partially redundant (refer to the same EquivalenceClasses). Therefore,
966  * what we do is convert the mergeclause list to a list of canonical
967  * pathkeys, and then consider different orderings of the pathkeys.
968  *
969  * Generating a path for *every* permutation of the pathkeys doesn't seem
970  * like a winning strategy; the cost in planning time is too high. For
971  * now, we generate one path for each pathkey, listing that pathkey first
972  * and the rest in random order. This should allow at least a one-clause
973  * mergejoin without re-sorting against any other possible mergejoin
974  * partner path. But if we've not guessed the right ordering of secondary
975  * keys, we may end up evaluating clauses as qpquals when they could have
976  * been done as mergeclauses. (In practice, it's rare that there's more
977  * than two or three mergeclauses, so expending a huge amount of thought
978  * on that is probably not worth it.)
979  *
980  * The pathkey order returned by select_outer_pathkeys_for_merge() has
981  * some heuristics behind it (see that function), so be sure to try it
982  * exactly as-is as well as making variants.
983  */
984  all_pathkeys = select_outer_pathkeys_for_merge(root,
985  extra->mergeclause_list,
986  joinrel);
987 
988  foreach(l, all_pathkeys)
989  {
990  List *front_pathkey = (List *) lfirst(l);
991  List *cur_mergeclauses;
992  List *outerkeys;
993  List *innerkeys;
994  List *merge_pathkeys;
995 
996  /* Make a pathkey list with this guy first */
997  if (l != list_head(all_pathkeys))
998  outerkeys = lcons(front_pathkey,
999  list_delete_ptr(list_copy(all_pathkeys),
1000  front_pathkey));
1001  else
1002  outerkeys = all_pathkeys; /* no work at first one... */
1003 
1004  /* Sort the mergeclauses into the corresponding ordering */
1005  cur_mergeclauses = find_mergeclauses_for_pathkeys(root,
1006  outerkeys,
1007  true,
1008  extra->mergeclause_list);
1009 
1010  /* Should have used them all... */
1011  Assert(list_length(cur_mergeclauses) == list_length(extra->mergeclause_list));
1012 
1013  /* Build sort pathkeys for the inner side */
1014  innerkeys = make_inner_pathkeys_for_merge(root,
1015  cur_mergeclauses,
1016  outerkeys);
1017 
1018  /* Build pathkeys representing output sort order */
1019  merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
1020  outerkeys);
1021 
1022  /*
1023  * And now we can make the path.
1024  *
1025  * Note: it's possible that the cheapest paths will already be sorted
1026  * properly. try_mergejoin_path will detect that case and suppress an
1027  * explicit sort step, so we needn't do so here.
1028  */
1029  try_mergejoin_path(root,
1030  joinrel,
1031  outer_path,
1032  inner_path,
1033  merge_pathkeys,
1034  cur_mergeclauses,
1035  outerkeys,
1036  innerkeys,
1037  jointype,
1038  extra,
1039  false);
1040 
1041  /*
1042  * If we have partial outer and parallel safe inner path then try
1043  * partial mergejoin path.
1044  */
1045  if (cheapest_partial_outer && cheapest_safe_inner)
1047  joinrel,
1048  cheapest_partial_outer,
1049  cheapest_safe_inner,
1050  merge_pathkeys,
1051  cur_mergeclauses,
1052  outerkeys,
1053  innerkeys,
1054  jointype,
1055  extra);
1056  }
1057 }
static void try_mergejoin_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, List *mergeclauses, List *outersortkeys, List *innersortkeys, JoinType jointype, JoinPathExtraData *extra, bool is_partial)
Definition: joinpath.c:555
#define NIL
Definition: pg_list.h:69
List * list_copy(const List *oldlist)
Definition: list.c:1160
List * make_inner_pathkeys_for_merge(PlannerInfo *root, List *mergeclauses, List *outer_pathkeys)
Definition: pathkeys.c:1292
List * partial_pathlist
Definition: relation.h:601
UniquePath * create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, SpecialJoinInfo *sjinfo)
Definition: pathnode.c:1440
List * list_delete_ptr(List *list, void *datum)
Definition: list.c:590
List * build_join_pathkeys(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, List *outer_pathkeys)
Definition: pathkeys.c:822
JoinType
Definition: nodes.h:674
Relids lateral_relids
Definition: relation.h:610
SpecialJoinInfo * sjinfo
Definition: relation.h:2273
#define linitial(l)
Definition: pg_list.h:111
struct Path * cheapest_total_path
Definition: relation.h:603
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
List * mergeclause_list
Definition: relation.h:2271
Path * get_cheapest_parallel_safe_total_inner(List *paths)
Definition: pathkeys.c:421
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:663
List * select_outer_pathkeys_for_merge(PlannerInfo *root, List *mergeclauses, RelOptInfo *joinrel)
Definition: pathkeys.c:1120
#define PATH_PARAM_BY_REL(path, rel)
Definition: joinpath.c:39
List * lcons(void *datum, List *list)
Definition: list.c:259
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
bool parallel_safe
Definition: relation.h:1048
static int list_length(const List *l)
Definition: pg_list.h:89
bool consider_parallel
Definition: relation.h:593
List * find_mergeclauses_for_pathkeys(PlannerInfo *root, List *pathkeys, bool outer_keys, List *restrictinfos)
Definition: pathkeys.c:1003
static void try_partial_mergejoin_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, List *mergeclauses, List *outersortkeys, List *innersortkeys, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:650
List * pathlist
Definition: relation.h:599
Definition: pg_list.h:45

◆ try_hashjoin_path()

static void try_hashjoin_path ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
List hashclauses,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 720 of file joinpath.c.

References add_path(), add_path_precheck(), bms_free(), bms_overlap(), calc_non_nestloop_required_outer(), create_hashjoin_path(), initial_cost_hashjoin(), NIL, JoinPathExtraData::param_source_rels, JoinPathExtraData::restrictlist, JoinCostWorkspace::startup_cost, and JoinCostWorkspace::total_cost.

Referenced by hash_inner_and_outer().

727 {
728  Relids required_outer;
729  JoinCostWorkspace workspace;
730 
731  /*
732  * Check to see if proposed path is still parameterized, and reject if the
733  * parameterization wouldn't be sensible.
734  */
735  required_outer = calc_non_nestloop_required_outer(outer_path,
736  inner_path);
737  if (required_outer &&
738  !bms_overlap(required_outer, extra->param_source_rels))
739  {
740  /* Waste no memory when we reject a path here */
741  bms_free(required_outer);
742  return;
743  }
744 
745  /*
746  * See comments in try_nestloop_path(). Also note that hashjoin paths
747  * never have any output pathkeys, per comments in create_hashjoin_path.
748  */
749  initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
750  outer_path, inner_path, extra);
751 
752  if (add_path_precheck(joinrel,
753  workspace.startup_cost, workspace.total_cost,
754  NIL, required_outer))
755  {
756  add_path(joinrel, (Path *)
758  joinrel,
759  jointype,
760  &workspace,
761  extra,
762  outer_path,
763  inner_path,
764  extra->restrictlist,
765  required_outer,
766  hashclauses));
767  }
768  else
769  {
770  /* Waste no memory when we reject a path here */
771  bms_free(required_outer);
772  }
773 }
#define NIL
Definition: pg_list.h:69
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:420
bool add_path_precheck(RelOptInfo *parent_rel, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
Definition: pathnode.c:655
void initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace, JoinType jointype, List *hashclauses, Path *outer_path, Path *inner_path, JoinPathExtraData *extra)
Definition: costsize.c:2965
Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path)
Definition: pathnode.c:2043
Relids param_source_rels
Definition: relation.h:2275
List * restrictlist
Definition: relation.h:2270
void bms_free(Bitmapset *a)
Definition: bitmapset.c:201
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
HashPath * create_hashjoin_path(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, Relids required_outer, List *hashclauses)
Definition: pathnode.c:2229

◆ try_mergejoin_path()

static void try_mergejoin_path ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
List pathkeys,
List mergeclauses,
List outersortkeys,
List innersortkeys,
JoinType  jointype,
JoinPathExtraData extra,
bool  is_partial 
)
static

Definition at line 555 of file joinpath.c.

References add_path(), add_path_precheck(), bms_free(), bms_overlap(), calc_non_nestloop_required_outer(), create_mergejoin_path(), initial_cost_mergejoin(), NIL, JoinPathExtraData::param_source_rels, Path::pathkeys, pathkeys_contained_in(), JoinPathExtraData::restrictlist, JoinCostWorkspace::startup_cost, JoinCostWorkspace::total_cost, and try_partial_mergejoin_path().

Referenced by generate_mergejoin_paths(), and sort_inner_and_outer().

566 {
567  Relids required_outer;
568  JoinCostWorkspace workspace;
569 
570  if (is_partial)
571  {
573  joinrel,
574  outer_path,
575  inner_path,
576  pathkeys,
577  mergeclauses,
578  outersortkeys,
579  innersortkeys,
580  jointype,
581  extra);
582  return;
583  }
584 
585  /*
586  * Check to see if proposed path is still parameterized, and reject if the
587  * parameterization wouldn't be sensible.
588  */
589  required_outer = calc_non_nestloop_required_outer(outer_path,
590  inner_path);
591  if (required_outer &&
592  !bms_overlap(required_outer, extra->param_source_rels))
593  {
594  /* Waste no memory when we reject a path here */
595  bms_free(required_outer);
596  return;
597  }
598 
599  /*
600  * If the given paths are already well enough ordered, we can skip doing
601  * an explicit sort.
602  */
603  if (outersortkeys &&
604  pathkeys_contained_in(outersortkeys, outer_path->pathkeys))
605  outersortkeys = NIL;
606  if (innersortkeys &&
607  pathkeys_contained_in(innersortkeys, inner_path->pathkeys))
608  innersortkeys = NIL;
609 
610  /*
611  * See comments in try_nestloop_path().
612  */
613  initial_cost_mergejoin(root, &workspace, jointype, mergeclauses,
614  outer_path, inner_path,
615  outersortkeys, innersortkeys,
616  extra);
617 
618  if (add_path_precheck(joinrel,
619  workspace.startup_cost, workspace.total_cost,
620  pathkeys, required_outer))
621  {
622  add_path(joinrel, (Path *)
624  joinrel,
625  jointype,
626  &workspace,
627  extra,
628  outer_path,
629  inner_path,
630  extra->restrictlist,
631  pathkeys,
632  required_outer,
633  mergeclauses,
634  outersortkeys,
635  innersortkeys));
636  }
637  else
638  {
639  /* Waste no memory when we reject a path here */
640  bms_free(required_outer);
641  }
642 }
#define NIL
Definition: pg_list.h:69
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:420
bool add_path_precheck(RelOptInfo *parent_rel, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
Definition: pathnode.c:655
Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path)
Definition: pathnode.c:2043
MergePath * create_mergejoin_path(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer, List *mergeclauses, List *outersortkeys, List *innersortkeys)
Definition: pathnode.c:2164
void initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace, JoinType jointype, List *mergeclauses, Path *outer_path, Path *inner_path, List *outersortkeys, List *innersortkeys, JoinPathExtraData *extra)
Definition: costsize.c:2414
Relids param_source_rels
Definition: relation.h:2275
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition: pathkeys.c:317
List * restrictlist
Definition: relation.h:2270
List * pathkeys
Definition: relation.h:1056
void bms_free(Bitmapset *a)
Definition: bitmapset.c:201
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
static void try_partial_mergejoin_path(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, List *pathkeys, List *mergeclauses, List *outersortkeys, List *innersortkeys, JoinType jointype, JoinPathExtraData *extra)
Definition: joinpath.c:650

◆ try_nestloop_path()

static void try_nestloop_path ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
List pathkeys,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 361 of file joinpath.c.

References add_path(), add_path_precheck(), allow_star_schema_join(), bms_free(), bms_overlap(), calc_nestloop_required_outer(), create_nestloop_path(), have_dangerous_phv(), initial_cost_nestloop(), JoinPathExtraData::param_source_rels, Path::parent, PATH_PARAM_BY_PARENT, PATH_REQ_OUTER, RelOptInfo::relids, reparameterize_path_by_child(), JoinPathExtraData::restrictlist, JoinCostWorkspace::startup_cost, RelOptInfo::top_parent_relids, and JoinCostWorkspace::total_cost.

Referenced by match_unsorted_outer().

368 {
369  Relids required_outer;
370  JoinCostWorkspace workspace;
371  RelOptInfo *innerrel = inner_path->parent;
372  RelOptInfo *outerrel = outer_path->parent;
373  Relids innerrelids;
374  Relids outerrelids;
375  Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
376  Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
377 
378  /*
379  * Paths are parameterized by top-level parents, so run parameterization
380  * tests on the parent relids.
381  */
382  if (innerrel->top_parent_relids)
383  innerrelids = innerrel->top_parent_relids;
384  else
385  innerrelids = innerrel->relids;
386 
387  if (outerrel->top_parent_relids)
388  outerrelids = outerrel->top_parent_relids;
389  else
390  outerrelids = outerrel->relids;
391 
392  /*
393  * Check to see if proposed path is still parameterized, and reject if the
394  * parameterization wouldn't be sensible --- unless allow_star_schema_join
395  * says to allow it anyway. Also, we must reject if have_dangerous_phv
396  * doesn't like the look of it, which could only happen if the nestloop is
397  * still parameterized.
398  */
399  required_outer = calc_nestloop_required_outer(outerrelids, outer_paramrels,
400  innerrelids, inner_paramrels);
401  if (required_outer &&
402  ((!bms_overlap(required_outer, extra->param_source_rels) &&
403  !allow_star_schema_join(root, outerrelids, inner_paramrels)) ||
404  have_dangerous_phv(root, outerrelids, inner_paramrels)))
405  {
406  /* Waste no memory when we reject a path here */
407  bms_free(required_outer);
408  return;
409  }
410 
411  /*
412  * Do a precheck to quickly eliminate obviously-inferior paths. We
413  * calculate a cheap lower bound on the path's cost and then use
414  * add_path_precheck() to see if the path is clearly going to be dominated
415  * by some existing path for the joinrel. If not, do the full pushup with
416  * creating a fully valid path structure and submitting it to add_path().
417  * The latter two steps are expensive enough to make this two-phase
418  * methodology worthwhile.
419  */
420  initial_cost_nestloop(root, &workspace, jointype,
421  outer_path, inner_path, extra);
422 
423  if (add_path_precheck(joinrel,
424  workspace.startup_cost, workspace.total_cost,
425  pathkeys, required_outer))
426  {
427  /*
428  * If the inner path is parameterized, it is parameterized by the
429  * topmost parent of the outer rel, not the outer rel itself. Fix
430  * that.
431  */
432  if (PATH_PARAM_BY_PARENT(inner_path, outer_path->parent))
433  {
434  inner_path = reparameterize_path_by_child(root, inner_path,
435  outer_path->parent);
436 
437  /*
438  * If we could not translate the path, we can't create nest loop
439  * path.
440  */
441  if (!inner_path)
442  {
443  bms_free(required_outer);
444  return;
445  }
446  }
447 
448  add_path(joinrel, (Path *)
450  joinrel,
451  jointype,
452  &workspace,
453  extra,
454  outer_path,
455  inner_path,
456  extra->restrictlist,
457  pathkeys,
458  required_outer));
459  }
460  else
461  {
462  /* Waste no memory when we reject a path here */
463  bms_free(required_outer);
464  }
465 }
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:420
bool add_path_precheck(RelOptInfo *parent_rel, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
Definition: pathnode.c:655
#define PATH_PARAM_BY_PARENT(path, rel)
Definition: joinpath.c:33
Relids param_source_rels
Definition: relation.h:2275
RelOptInfo * parent
Definition: relation.h:1042
Path * reparameterize_path_by_child(PlannerInfo *root, Path *path, RelOptInfo *child_rel)
Definition: pathnode.c:3497
NestPath * create_nestloop_path(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer)
Definition: pathnode.c:2076
Relids relids
Definition: relation.h:585
List * restrictlist
Definition: relation.h:2270
void bms_free(Bitmapset *a)
Definition: bitmapset.c:201
#define PATH_REQ_OUTER(path)
Definition: relation.h:1061
Relids calc_nestloop_required_outer(Relids outerrelids, Relids outer_paramrels, Relids innerrelids, Relids inner_paramrels)
Definition: pathnode.c:2010
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
void initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace, JoinType jointype, Path *outer_path, Path *inner_path, JoinPathExtraData *extra)
Definition: costsize.c:2132
static bool allow_star_schema_join(PlannerInfo *root, Relids outerrelids, Relids inner_paramrels)
Definition: joinpath.c:343
bool have_dangerous_phv(PlannerInfo *root, Relids outer_relids, Relids inner_params)
Definition: joinrels.c:1167
Relids top_parent_relids
Definition: relation.h:654

◆ try_partial_hashjoin_path()

static void try_partial_hashjoin_path ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
List hashclauses,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 781 of file joinpath.c.

References add_partial_path(), add_partial_path_precheck(), Assert, bms_is_empty(), create_hashjoin_path(), initial_cost_hashjoin(), RelOptInfo::lateral_relids, NIL, Path::param_info, ParamPathInfo::ppi_req_outer, JoinPathExtraData::restrictlist, and JoinCostWorkspace::total_cost.

Referenced by hash_inner_and_outer().

788 {
789  JoinCostWorkspace workspace;
790 
791  /*
792  * If the inner path is parameterized, the parameterization must be fully
793  * satisfied by the proposed outer path. Parameterized partial paths are
794  * not supported. The caller should already have verified that no
795  * extra_lateral_rels are required here.
796  */
798  if (inner_path->param_info != NULL)
799  {
800  Relids inner_paramrels = inner_path->param_info->ppi_req_outer;
801 
802  if (!bms_is_empty(inner_paramrels))
803  return;
804  }
805 
806  /*
807  * Before creating a path, get a quick lower bound on what it is likely to
808  * cost. Bail out right away if it looks terrible.
809  */
810  initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
811  outer_path, inner_path, extra);
812  if (!add_partial_path_precheck(joinrel, workspace.total_cost, NIL))
813  return;
814 
815  /* Might be good enough to be worth trying, so let's try it. */
816  add_partial_path(joinrel, (Path *)
818  joinrel,
819  jointype,
820  &workspace,
821  extra,
822  outer_path,
823  inner_path,
824  extra->restrictlist,
825  NULL,
826  hashclauses));
827 }
#define NIL
Definition: pg_list.h:69
bool add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost, List *pathkeys)
Definition: pathnode.c:884
ParamPathInfo * param_info
Definition: relation.h:1045
void initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace, JoinType jointype, List *hashclauses, Path *outer_path, Path *inner_path, JoinPathExtraData *extra)
Definition: costsize.c:2965
Relids lateral_relids
Definition: relation.h:610
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:663
List * restrictlist
Definition: relation.h:2270
#define Assert(condition)
Definition: c.h:670
HashPath * create_hashjoin_path(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, Relids required_outer, List *hashclauses)
Definition: pathnode.c:2229
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:760
Relids ppi_req_outer
Definition: relation.h:1001

◆ try_partial_mergejoin_path()

static void try_partial_mergejoin_path ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
List pathkeys,
List mergeclauses,
List outersortkeys,
List innersortkeys,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 650 of file joinpath.c.

References add_partial_path(), add_partial_path_precheck(), Assert, bms_is_empty(), create_mergejoin_path(), initial_cost_mergejoin(), RelOptInfo::lateral_relids, NIL, Path::param_info, Path::pathkeys, pathkeys_contained_in(), ParamPathInfo::ppi_req_outer, JoinPathExtraData::restrictlist, and JoinCostWorkspace::total_cost.

Referenced by sort_inner_and_outer(), and try_mergejoin_path().

660 {
661  JoinCostWorkspace workspace;
662 
663  /*
664  * See comments in try_partial_hashjoin_path().
665  */
667  if (inner_path->param_info != NULL)
668  {
669  Relids inner_paramrels = inner_path->param_info->ppi_req_outer;
670 
671  if (!bms_is_empty(inner_paramrels))
672  return;
673  }
674 
675  /*
676  * If the given paths are already well enough ordered, we can skip doing
677  * an explicit sort.
678  */
679  if (outersortkeys &&
680  pathkeys_contained_in(outersortkeys, outer_path->pathkeys))
681  outersortkeys = NIL;
682  if (innersortkeys &&
683  pathkeys_contained_in(innersortkeys, inner_path->pathkeys))
684  innersortkeys = NIL;
685 
686  /*
687  * See comments in try_partial_nestloop_path().
688  */
689  initial_cost_mergejoin(root, &workspace, jointype, mergeclauses,
690  outer_path, inner_path,
691  outersortkeys, innersortkeys,
692  extra);
693 
694  if (!add_partial_path_precheck(joinrel, workspace.total_cost, pathkeys))
695  return;
696 
697  /* Might be good enough to be worth trying, so let's try it. */
698  add_partial_path(joinrel, (Path *)
700  joinrel,
701  jointype,
702  &workspace,
703  extra,
704  outer_path,
705  inner_path,
706  extra->restrictlist,
707  pathkeys,
708  NULL,
709  mergeclauses,
710  outersortkeys,
711  innersortkeys));
712 }
#define NIL
Definition: pg_list.h:69
bool add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost, List *pathkeys)
Definition: pathnode.c:884
ParamPathInfo * param_info
Definition: relation.h:1045
MergePath * create_mergejoin_path(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer, List *mergeclauses, List *outersortkeys, List *innersortkeys)
Definition: pathnode.c:2164
void initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace, JoinType jointype, List *mergeclauses, Path *outer_path, Path *inner_path, List *outersortkeys, List *innersortkeys, JoinPathExtraData *extra)
Definition: costsize.c:2414
Relids lateral_relids
Definition: relation.h:610
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:663
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition: pathkeys.c:317
List * restrictlist
Definition: relation.h:2270
List * pathkeys
Definition: relation.h:1056
#define Assert(condition)
Definition: c.h:670
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:760
Relids ppi_req_outer
Definition: relation.h:1001

◆ try_partial_nestloop_path()

static void try_partial_nestloop_path ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
List pathkeys,
JoinType  jointype,
JoinPathExtraData extra 
)
static

Definition at line 473 of file joinpath.c.

References add_partial_path(), add_partial_path_precheck(), Assert, bms_is_empty(), bms_is_subset(), create_nestloop_path(), initial_cost_nestloop(), RelOptInfo::lateral_relids, Path::param_info, Path::parent, PATH_PARAM_BY_PARENT, ParamPathInfo::ppi_req_outer, RelOptInfo::relids, reparameterize_path_by_child(), JoinPathExtraData::restrictlist, RelOptInfo::top_parent_relids, and JoinCostWorkspace::total_cost.

Referenced by consider_parallel_nestloop().

480 {
481  JoinCostWorkspace workspace;
482 
483  /*
484  * If the inner path is parameterized, the parameterization must be fully
485  * satisfied by the proposed outer path. Parameterized partial paths are
486  * not supported. The caller should already have verified that no
487  * extra_lateral_rels are required here.
488  */
490  if (inner_path->param_info != NULL)
491  {
492  Relids inner_paramrels = inner_path->param_info->ppi_req_outer;
493  RelOptInfo *outerrel = outer_path->parent;
494  Relids outerrelids;
495 
496  /*
497  * The inner and outer paths are parameterized, if at all, by the top
498  * level parents, not the child relations, so we must use those relids
499  * for our paramaterization tests.
500  */
501  if (outerrel->top_parent_relids)
502  outerrelids = outerrel->top_parent_relids;
503  else
504  outerrelids = outerrel->relids;
505 
506  if (!bms_is_subset(inner_paramrels, outerrelids))
507  return;
508  }
509 
510  /*
511  * Before creating a path, get a quick lower bound on what it is likely to
512  * cost. Bail out right away if it looks terrible.
513  */
514  initial_cost_nestloop(root, &workspace, jointype,
515  outer_path, inner_path, extra);
516  if (!add_partial_path_precheck(joinrel, workspace.total_cost, pathkeys))
517  return;
518 
519  /*
520  * If the inner path is parameterized, it is parameterized by the topmost
521  * parent of the outer rel, not the outer rel itself. Fix that.
522  */
523  if (PATH_PARAM_BY_PARENT(inner_path, outer_path->parent))
524  {
525  inner_path = reparameterize_path_by_child(root, inner_path,
526  outer_path->parent);
527 
528  /*
529  * If we could not translate the path, we can't create nest loop path.
530  */
531  if (!inner_path)
532  return;
533  }
534 
535  /* Might be good enough to be worth trying, so let's try it. */
536  add_partial_path(joinrel, (Path *)
538  joinrel,
539  jointype,
540  &workspace,
541  extra,
542  outer_path,
543  inner_path,
544  extra->restrictlist,
545  pathkeys,
546  NULL));
547 }
bool add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost, List *pathkeys)
Definition: pathnode.c:884
ParamPathInfo * param_info
Definition: relation.h:1045
#define PATH_PARAM_BY_PARENT(path, rel)
Definition: joinpath.c:33
Relids lateral_relids
Definition: relation.h:610
RelOptInfo * parent
Definition: relation.h:1042
Path * reparameterize_path_by_child(PlannerInfo *root, Path *path, RelOptInfo *child_rel)
Definition: pathnode.c:3497
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
NestPath * create_nestloop_path(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer)
Definition: pathnode.c:2076
Relids relids
Definition: relation.h:585
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:663
List * restrictlist
Definition: relation.h:2270
#define Assert(condition)
Definition: c.h:670
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:760
void initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace, JoinType jointype, Path *outer_path, Path *inner_path, JoinPathExtraData *extra)
Definition: costsize.c:2132
Relids ppi_req_outer
Definition: relation.h:1001
Relids top_parent_relids
Definition: relation.h:654

Variable Documentation

◆ set_join_pathlist_hook

set_join_pathlist_hook_type set_join_pathlist_hook = NULL

Definition at line 27 of file joinpath.c.

Referenced by add_paths_to_joinrel().