PostgreSQL Source Code  git master
pathnode.h File Reference
#include "nodes/bitmapset.h"
#include "nodes/pathnodes.h"
Include dependency graph for pathnode.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int compare_path_costs (Path *path1, Path *path2, CostSelector criterion)
 
int compare_fractional_path_costs (Path *path1, Path *path2, double fraction)
 
void set_cheapest (RelOptInfo *parent_rel)
 
void add_path (RelOptInfo *parent_rel, Path *new_path)
 
bool add_path_precheck (RelOptInfo *parent_rel, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
 
void add_partial_path (RelOptInfo *parent_rel, Path *new_path)
 
bool add_partial_path_precheck (RelOptInfo *parent_rel, Cost total_cost, List *pathkeys)
 
Pathcreate_seqscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
 
Pathcreate_samplescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
IndexPathcreate_index_path (PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
 
BitmapHeapPathcreate_bitmap_heap_path (PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
 
BitmapAndPathcreate_bitmap_and_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
BitmapOrPathcreate_bitmap_or_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
TidPathcreate_tidscan_path (PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
 
TidRangePathcreate_tidrangescan_path (PlannerInfo *root, RelOptInfo *rel, List *tidrangequals, Relids required_outer)
 
AppendPathcreate_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *partial_subpaths, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath)
 
MemoizePathcreate_memoize_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, double calls)
 
UniquePathcreate_unique_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, SpecialJoinInfo *sjinfo)
 
GatherPathcreate_gather_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
 
GatherMergePathcreate_gather_merge_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *pathkeys, Relids required_outer, double *rows)
 
SubqueryScanPathcreate_subqueryscan_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, Relids required_outer)
 
Pathcreate_functionscan_path (PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer)
 
Pathcreate_valuesscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_tablefuncscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_ctescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_namedtuplestorescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_resultscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_worktablescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
ForeignPathcreate_foreignscan_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_private)
 
ForeignPathcreate_foreign_join_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_private)
 
ForeignPathcreate_foreign_upper_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Path *fdw_outerpath, List *fdw_private)
 
Relids calc_nestloop_required_outer (Relids outerrelids, Relids outer_paramrels, Relids innerrelids, Relids inner_paramrels)
 
Relids calc_non_nestloop_required_outer (Path *outer_path, Path *inner_path)
 
NestPathcreate_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)
 
MergePathcreate_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)
 
HashPathcreate_hashjoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, bool parallel_hash, List *restrict_clauses, Relids required_outer, List *hashclauses)
 
ProjectionPathcreate_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
Pathapply_projection_to_path (PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
 
ProjectSetPathcreate_set_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
SortPathcreate_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
 
IncrementalSortPathcreate_incremental_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
 
GroupPathcreate_group_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *groupClause, List *qual, double numGroups)
 
UpperUniquePathcreate_upper_unique_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
 
AggPathcreate_agg_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, AggStrategy aggstrategy, AggSplit aggsplit, List *groupClause, List *qual, const AggClauseCosts *aggcosts, double numGroups)
 
GroupingSetsPathcreate_groupingsets_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *having_qual, AggStrategy aggstrategy, List *rollups, const AggClauseCosts *agg_costs, double numGroups)
 
MinMaxAggPathcreate_minmaxagg_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *mmaggregates, List *quals)
 
WindowAggPathcreate_windowagg_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *windowFuncs, WindowClause *winclause, List *qual, bool topwindow)
 
SetOpPathcreate_setop_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, SetOpCmd cmd, SetOpStrategy strategy, List *distinctList, AttrNumber flagColIdx, int firstFlag, double numGroups, double outputRows)
 
RecursiveUnionPathcreate_recursiveunion_path (PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
 
LockRowsPathcreate_lockrows_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *rowMarks, int epqParam)
 
ModifyTablePathcreate_modifytable_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, CmdType operation, bool canSetTag, Index nominalRelation, Index rootRelation, bool partColsUpdated, List *resultRelations, List *updateColnosLists, List *withCheckOptionLists, List *returningLists, List *rowMarks, OnConflictExpr *onconflict, List *mergeActionLists, int epqParam)
 
LimitPathcreate_limit_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, Node *limitOffset, Node *limitCount, LimitOption limitOption, int64 offset_est, int64 count_est)
 
void adjust_limit_rows_costs (double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
 
Pathreparameterize_path (PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
 
Pathreparameterize_path_by_child (PlannerInfo *root, Path *path, RelOptInfo *child_rel)
 
void setup_simple_rel_arrays (PlannerInfo *root)
 
void expand_planner_arrays (PlannerInfo *root, int add_size)
 
RelOptInfobuild_simple_rel (PlannerInfo *root, int relid, RelOptInfo *parent)
 
RelOptInfofind_base_rel (PlannerInfo *root, int relid)
 
RelOptInfofind_join_rel (PlannerInfo *root, Relids relids)
 
RelOptInfobuild_join_rel (PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List **restrictlist_ptr)
 
Relids min_join_parameterization (PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
 
RelOptInfofetch_upper_rel (PlannerInfo *root, UpperRelationKind kind, Relids relids)
 
Relids find_childrel_parents (PlannerInfo *root, RelOptInfo *rel)
 
ParamPathInfoget_baserel_parampathinfo (PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
 
ParamPathInfoget_joinrel_parampathinfo (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, Relids required_outer, List **restrict_clauses)
 
ParamPathInfoget_appendrel_parampathinfo (RelOptInfo *appendrel, Relids required_outer)
 
ParamPathInfofind_param_path_info (RelOptInfo *rel, Relids required_outer)
 
RelOptInfobuild_child_join_rel (PlannerInfo *root, RelOptInfo *outer_rel, RelOptInfo *inner_rel, RelOptInfo *parent_joinrel, List *restrictlist, SpecialJoinInfo *sjinfo, JoinType jointype)
 

Function Documentation

◆ add_partial_path()

void add_partial_path ( RelOptInfo parent_rel,
Path new_path 
)

Definition at line 749 of file pathnode.c.

750 {
751  bool accept_new = true; /* unless we find a superior old path */
752  int insert_at = 0; /* where to insert new item */
753  ListCell *p1;
754 
755  /* Check for query cancel. */
757 
758  /* Path to be added must be parallel safe. */
759  Assert(new_path->parallel_safe);
760 
761  /* Relation should be OK for parallelism, too. */
762  Assert(parent_rel->consider_parallel);
763 
764  /*
765  * As in add_path, throw out any paths which are dominated by the new
766  * path, but throw out the new path if some existing path dominates it.
767  */
768  foreach(p1, parent_rel->partial_pathlist)
769  {
770  Path *old_path = (Path *) lfirst(p1);
771  bool remove_old = false; /* unless new proves superior */
772  PathKeysComparison keyscmp;
773 
774  /* Compare pathkeys. */
775  keyscmp = compare_pathkeys(new_path->pathkeys, old_path->pathkeys);
776 
777  /* Unless pathkeys are incompatible, keep just one of the two paths. */
778  if (keyscmp != PATHKEYS_DIFFERENT)
779  {
780  if (new_path->total_cost > old_path->total_cost * STD_FUZZ_FACTOR)
781  {
782  /* New path costs more; keep it only if pathkeys are better. */
783  if (keyscmp != PATHKEYS_BETTER1)
784  accept_new = false;
785  }
786  else if (old_path->total_cost > new_path->total_cost
787  * STD_FUZZ_FACTOR)
788  {
789  /* Old path costs more; keep it only if pathkeys are better. */
790  if (keyscmp != PATHKEYS_BETTER2)
791  remove_old = true;
792  }
793  else if (keyscmp == PATHKEYS_BETTER1)
794  {
795  /* Costs are about the same, new path has better pathkeys. */
796  remove_old = true;
797  }
798  else if (keyscmp == PATHKEYS_BETTER2)
799  {
800  /* Costs are about the same, old path has better pathkeys. */
801  accept_new = false;
802  }
803  else if (old_path->total_cost > new_path->total_cost * 1.0000000001)
804  {
805  /* Pathkeys are the same, and the old path costs more. */
806  remove_old = true;
807  }
808  else
809  {
810  /*
811  * Pathkeys are the same, and new path isn't materially
812  * cheaper.
813  */
814  accept_new = false;
815  }
816  }
817 
818  /*
819  * Remove current element from partial_pathlist if dominated by new.
820  */
821  if (remove_old)
822  {
823  parent_rel->partial_pathlist =
824  foreach_delete_current(parent_rel->partial_pathlist, p1);
825  pfree(old_path);
826  }
827  else
828  {
829  /* new belongs after this old path if it has cost >= old's */
830  if (new_path->total_cost >= old_path->total_cost)
831  insert_at = foreach_current_index(p1) + 1;
832  }
833 
834  /*
835  * If we found an old path that dominates new_path, we can quit
836  * scanning the partial_pathlist; we will not add new_path, and we
837  * assume new_path cannot dominate any later path.
838  */
839  if (!accept_new)
840  break;
841  }
842 
843  if (accept_new)
844  {
845  /* Accept the new path: insert it at proper place */
846  parent_rel->partial_pathlist =
847  list_insert_nth(parent_rel->partial_pathlist, insert_at, new_path);
848  }
849  else
850  {
851  /* Reject and recycle the new path */
852  pfree(new_path);
853  }
854 }
Assert(fmt[strlen(fmt) - 1] !='\n')
List * list_insert_nth(List *list, int pos, void *datum)
Definition: list.c:418
void pfree(void *pointer)
Definition: mcxt.c:1175
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
PathKeysComparison compare_pathkeys(List *keys1, List *keys2)
Definition: pathkeys.c:290
#define STD_FUZZ_FACTOR
Definition: pathnode.c:51
PathKeysComparison
Definition: paths.h:196
@ PATHKEYS_BETTER2
Definition: paths.h:199
@ PATHKEYS_BETTER1
Definition: paths.h:198
@ PATHKEYS_DIFFERENT
Definition: paths.h:200
#define lfirst(lc)
Definition: pg_list.h:169
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
#define foreach_current_index(cell)
Definition: pg_list.h:382
List * pathkeys
Definition: pathnodes.h:1208
Cost total_cost
Definition: pathnodes.h:1206
bool parallel_safe
Definition: pathnodes.h:1200
bool consider_parallel
Definition: pathnodes.h:690
List * partial_pathlist
Definition: pathnodes.h:698

References Assert(), CHECK_FOR_INTERRUPTS, compare_pathkeys(), RelOptInfo::consider_parallel, foreach_current_index, foreach_delete_current, lfirst, list_insert_nth(), Path::parallel_safe, RelOptInfo::partial_pathlist, Path::pathkeys, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, pfree(), STD_FUZZ_FACTOR, and Path::total_cost.

Referenced by add_paths_to_append_rel(), build_index_paths(), create_partial_bitmap_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), create_plain_partial_paths(), grouping_planner(), recurse_set_operations(), set_subquery_pathlist(), try_partial_hashjoin_path(), try_partial_mergejoin_path(), and try_partial_nestloop_path().

◆ add_partial_path_precheck()

bool add_partial_path_precheck ( RelOptInfo parent_rel,
Cost  total_cost,
List pathkeys 
)

Definition at line 867 of file pathnode.c.

869 {
870  ListCell *p1;
871 
872  /*
873  * Our goal here is twofold. First, we want to find out whether this path
874  * is clearly inferior to some existing partial path. If so, we want to
875  * reject it immediately. Second, we want to find out whether this path
876  * is clearly superior to some existing partial path -- at least, modulo
877  * final cost computations. If so, we definitely want to consider it.
878  *
879  * Unlike add_path(), we always compare pathkeys here. This is because we
880  * expect partial_pathlist to be very short, and getting a definitive
881  * answer at this stage avoids the need to call add_path_precheck.
882  */
883  foreach(p1, parent_rel->partial_pathlist)
884  {
885  Path *old_path = (Path *) lfirst(p1);
886  PathKeysComparison keyscmp;
887 
888  keyscmp = compare_pathkeys(pathkeys, old_path->pathkeys);
889  if (keyscmp != PATHKEYS_DIFFERENT)
890  {
891  if (total_cost > old_path->total_cost * STD_FUZZ_FACTOR &&
892  keyscmp != PATHKEYS_BETTER1)
893  return false;
894  if (old_path->total_cost > total_cost * STD_FUZZ_FACTOR &&
895  keyscmp != PATHKEYS_BETTER2)
896  return true;
897  }
898  }
899 
900  /*
901  * This path is neither clearly inferior to an existing partial path nor
902  * clearly good enough that it might replace one. Compare it to
903  * non-parallel plans. If it loses even before accounting for the cost of
904  * the Gather node, we should definitely reject it.
905  *
906  * Note that we pass the total_cost to add_path_precheck twice. This is
907  * because it's never advantageous to consider the startup cost of a
908  * partial path; the resulting plans, if run in parallel, will be run to
909  * completion.
910  */
911  if (!add_path_precheck(parent_rel, total_cost, total_cost, pathkeys,
912  NULL))
913  return false;
914 
915  return true;
916 }
bool add_path_precheck(RelOptInfo *parent_rel, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
Definition: pathnode.c:644

References add_path_precheck(), compare_pathkeys(), lfirst, RelOptInfo::partial_pathlist, Path::pathkeys, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, STD_FUZZ_FACTOR, and Path::total_cost.

Referenced by try_partial_hashjoin_path(), try_partial_mergejoin_path(), and try_partial_nestloop_path().

◆ add_path()

void add_path ( RelOptInfo parent_rel,
Path new_path 
)

Definition at line 422 of file pathnode.c.

423 {
424  bool accept_new = true; /* unless we find a superior old path */
425  int insert_at = 0; /* where to insert new item */
426  List *new_path_pathkeys;
427  ListCell *p1;
428 
429  /*
430  * This is a convenient place to check for query cancel --- no part of the
431  * planner goes very long without calling add_path().
432  */
434 
435  /* Pretend parameterized paths have no pathkeys, per comment above */
436  new_path_pathkeys = new_path->param_info ? NIL : new_path->pathkeys;
437 
438  /*
439  * Loop to check proposed new path against old paths. Note it is possible
440  * for more than one old path to be tossed out because new_path dominates
441  * it.
442  */
443  foreach(p1, parent_rel->pathlist)
444  {
445  Path *old_path = (Path *) lfirst(p1);
446  bool remove_old = false; /* unless new proves superior */
447  PathCostComparison costcmp;
448  PathKeysComparison keyscmp;
449  BMS_Comparison outercmp;
450 
451  /*
452  * Do a fuzzy cost comparison with standard fuzziness limit.
453  */
454  costcmp = compare_path_costs_fuzzily(new_path, old_path,
456 
457  /*
458  * If the two paths compare differently for startup and total cost,
459  * then we want to keep both, and we can skip comparing pathkeys and
460  * required_outer rels. If they compare the same, proceed with the
461  * other comparisons. Row count is checked last. (We make the tests
462  * in this order because the cost comparison is most likely to turn
463  * out "different", and the pathkeys comparison next most likely. As
464  * explained above, row count very seldom makes a difference, so even
465  * though it's cheap to compare there's not much point in checking it
466  * earlier.)
467  */
468  if (costcmp != COSTS_DIFFERENT)
469  {
470  /* Similarly check to see if either dominates on pathkeys */
471  List *old_path_pathkeys;
472 
473  old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
474  keyscmp = compare_pathkeys(new_path_pathkeys,
475  old_path_pathkeys);
476  if (keyscmp != PATHKEYS_DIFFERENT)
477  {
478  switch (costcmp)
479  {
480  case COSTS_EQUAL:
481  outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
482  PATH_REQ_OUTER(old_path));
483  if (keyscmp == PATHKEYS_BETTER1)
484  {
485  if ((outercmp == BMS_EQUAL ||
486  outercmp == BMS_SUBSET1) &&
487  new_path->rows <= old_path->rows &&
488  new_path->parallel_safe >= old_path->parallel_safe)
489  remove_old = true; /* new dominates old */
490  }
491  else if (keyscmp == PATHKEYS_BETTER2)
492  {
493  if ((outercmp == BMS_EQUAL ||
494  outercmp == BMS_SUBSET2) &&
495  new_path->rows >= old_path->rows &&
496  new_path->parallel_safe <= old_path->parallel_safe)
497  accept_new = false; /* old dominates new */
498  }
499  else /* keyscmp == PATHKEYS_EQUAL */
500  {
501  if (outercmp == BMS_EQUAL)
502  {
503  /*
504  * Same pathkeys and outer rels, and fuzzily
505  * the same cost, so keep just one; to decide
506  * which, first check parallel-safety, then
507  * rows, then do a fuzzy cost comparison with
508  * very small fuzz limit. (We used to do an
509  * exact cost comparison, but that results in
510  * annoying platform-specific plan variations
511  * due to roundoff in the cost estimates.) If
512  * things are still tied, arbitrarily keep
513  * only the old path. Notice that we will
514  * keep only the old path even if the
515  * less-fuzzy comparison decides the startup
516  * and total costs compare differently.
517  */
518  if (new_path->parallel_safe >
519  old_path->parallel_safe)
520  remove_old = true; /* new dominates old */
521  else if (new_path->parallel_safe <
522  old_path->parallel_safe)
523  accept_new = false; /* old dominates new */
524  else if (new_path->rows < old_path->rows)
525  remove_old = true; /* new dominates old */
526  else if (new_path->rows > old_path->rows)
527  accept_new = false; /* old dominates new */
528  else if (compare_path_costs_fuzzily(new_path,
529  old_path,
530  1.0000000001) == COSTS_BETTER1)
531  remove_old = true; /* new dominates old */
532  else
533  accept_new = false; /* old equals or
534  * dominates new */
535  }
536  else if (outercmp == BMS_SUBSET1 &&
537  new_path->rows <= old_path->rows &&
538  new_path->parallel_safe >= old_path->parallel_safe)
539  remove_old = true; /* new dominates old */
540  else if (outercmp == BMS_SUBSET2 &&
541  new_path->rows >= old_path->rows &&
542  new_path->parallel_safe <= old_path->parallel_safe)
543  accept_new = false; /* old dominates new */
544  /* else different parameterizations, keep both */
545  }
546  break;
547  case COSTS_BETTER1:
548  if (keyscmp != PATHKEYS_BETTER2)
549  {
550  outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
551  PATH_REQ_OUTER(old_path));
552  if ((outercmp == BMS_EQUAL ||
553  outercmp == BMS_SUBSET1) &&
554  new_path->rows <= old_path->rows &&
555  new_path->parallel_safe >= old_path->parallel_safe)
556  remove_old = true; /* new dominates old */
557  }
558  break;
559  case COSTS_BETTER2:
560  if (keyscmp != PATHKEYS_BETTER1)
561  {
562  outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
563  PATH_REQ_OUTER(old_path));
564  if ((outercmp == BMS_EQUAL ||
565  outercmp == BMS_SUBSET2) &&
566  new_path->rows >= old_path->rows &&
567  new_path->parallel_safe <= old_path->parallel_safe)
568  accept_new = false; /* old dominates new */
569  }
570  break;
571  case COSTS_DIFFERENT:
572 
573  /*
574  * can't get here, but keep this case to keep compiler
575  * quiet
576  */
577  break;
578  }
579  }
580  }
581 
582  /*
583  * Remove current element from pathlist if dominated by new.
584  */
585  if (remove_old)
586  {
587  parent_rel->pathlist = foreach_delete_current(parent_rel->pathlist,
588  p1);
589 
590  /*
591  * Delete the data pointed-to by the deleted cell, if possible
592  */
593  if (!IsA(old_path, IndexPath))
594  pfree(old_path);
595  }
596  else
597  {
598  /* new belongs after this old path if it has cost >= old's */
599  if (new_path->total_cost >= old_path->total_cost)
600  insert_at = foreach_current_index(p1) + 1;
601  }
602 
603  /*
604  * If we found an old path that dominates new_path, we can quit
605  * scanning the pathlist; we will not add new_path, and we assume
606  * new_path cannot dominate any other elements of the pathlist.
607  */
608  if (!accept_new)
609  break;
610  }
611 
612  if (accept_new)
613  {
614  /* Accept the new path: insert it at proper place in pathlist */
615  parent_rel->pathlist =
616  list_insert_nth(parent_rel->pathlist, insert_at, new_path);
617  }
618  else
619  {
620  /* Reject and recycle the new path */
621  if (!IsA(new_path, IndexPath))
622  pfree(new_path);
623  }
624 }
BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:352
BMS_Comparison
Definition: bitmapset.h:58
@ BMS_SUBSET1
Definition: bitmapset.h:60
@ BMS_EQUAL
Definition: bitmapset.h:59
@ BMS_SUBSET2
Definition: bitmapset.h:61
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
static PathCostComparison compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
Definition: pathnode.c:166
PathCostComparison
Definition: pathnode.c:39
@ COSTS_EQUAL
Definition: pathnode.c:40
@ COSTS_BETTER1
Definition: pathnode.c:41
@ COSTS_BETTER2
Definition: pathnode.c:42
@ COSTS_DIFFERENT
Definition: pathnode.c:43
#define PATH_REQ_OUTER(path)
Definition: pathnodes.h:1213
#define NIL
Definition: pg_list.h:65
Definition: pg_list.h:51
Cardinality rows
Definition: pathnodes.h:1204
ParamPathInfo * param_info
Definition: pathnodes.h:1197
List * pathlist
Definition: pathnodes.h:696

References BMS_EQUAL, BMS_SUBSET1, BMS_SUBSET2, bms_subset_compare(), CHECK_FOR_INTERRUPTS, compare_path_costs_fuzzily(), compare_pathkeys(), COSTS_BETTER1, COSTS_BETTER2, COSTS_DIFFERENT, COSTS_EQUAL, foreach_current_index, foreach_delete_current, IsA, lfirst, list_insert_nth(), NIL, Path::parallel_safe, Path::param_info, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, RelOptInfo::pathlist, pfree(), Path::rows, STD_FUZZ_FACTOR, and Path::total_cost.

Referenced by add_foreign_final_paths(), add_foreign_grouping_paths(), add_foreign_ordered_paths(), add_paths_to_append_rel(), add_paths_to_grouping_rel(), add_paths_with_pathkeys_for_rel(), BuildParameterizedTidPaths(), consider_groupingsets_paths(), create_degenerate_grouping_paths(), create_final_distinct_paths(), create_index_paths(), create_one_window_path(), create_ordered_paths(), create_partial_grouping_paths(), create_tidscan_paths(), fileGetForeignPaths(), gather_grouping_paths(), generate_gather_paths(), generate_nonunion_paths(), generate_orderedappend_paths(), generate_recursion_path(), generate_union_paths(), generate_useful_gather_paths(), get_index_paths(), grouping_planner(), mark_dummy_rel(), postgresGetForeignJoinPaths(), postgresGetForeignPaths(), preprocess_minmax_aggregates(), query_planner(), recurse_set_operations(), set_cte_pathlist(), set_dummy_rel_pathlist(), set_function_pathlist(), set_namedtuplestore_pathlist(), set_plain_rel_pathlist(), set_result_pathlist(), set_subquery_pathlist(), set_tablefunc_pathlist(), set_tablesample_rel_pathlist(), set_values_pathlist(), set_worktable_pathlist(), try_hashjoin_path(), try_mergejoin_path(), and try_nestloop_path().

◆ add_path_precheck()

bool add_path_precheck ( RelOptInfo parent_rel,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer 
)

Definition at line 644 of file pathnode.c.

647 {
648  List *new_path_pathkeys;
649  bool consider_startup;
650  ListCell *p1;
651 
652  /* Pretend parameterized paths have no pathkeys, per add_path policy */
653  new_path_pathkeys = required_outer ? NIL : pathkeys;
654 
655  /* Decide whether new path's startup cost is interesting */
656  consider_startup = required_outer ? parent_rel->consider_param_startup : parent_rel->consider_startup;
657 
658  foreach(p1, parent_rel->pathlist)
659  {
660  Path *old_path = (Path *) lfirst(p1);
661  PathKeysComparison keyscmp;
662 
663  /*
664  * We are looking for an old_path with the same parameterization (and
665  * by assumption the same rowcount) that dominates the new path on
666  * pathkeys as well as both cost metrics. If we find one, we can
667  * reject the new path.
668  *
669  * Cost comparisons here should match compare_path_costs_fuzzily.
670  */
671  if (total_cost > old_path->total_cost * STD_FUZZ_FACTOR)
672  {
673  /* new path can win on startup cost only if consider_startup */
674  if (startup_cost > old_path->startup_cost * STD_FUZZ_FACTOR ||
675  !consider_startup)
676  {
677  /* new path loses on cost, so check pathkeys... */
678  List *old_path_pathkeys;
679 
680  old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
681  keyscmp = compare_pathkeys(new_path_pathkeys,
682  old_path_pathkeys);
683  if (keyscmp == PATHKEYS_EQUAL ||
684  keyscmp == PATHKEYS_BETTER2)
685  {
686  /* new path does not win on pathkeys... */
687  if (bms_equal(required_outer, PATH_REQ_OUTER(old_path)))
688  {
689  /* Found an old path that dominates the new one */
690  return false;
691  }
692  }
693  }
694  }
695  else
696  {
697  /*
698  * Since the pathlist is sorted by total_cost, we can stop looking
699  * once we reach a path with a total_cost larger than the new
700  * path's.
701  */
702  break;
703  }
704  }
705 
706  return true;
707 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:94
@ PATHKEYS_EQUAL
Definition: paths.h:197
Cost startup_cost
Definition: pathnodes.h:1205
bool consider_param_startup
Definition: pathnodes.h:689
bool consider_startup
Definition: pathnodes.h:688

References bms_equal(), compare_pathkeys(), RelOptInfo::consider_param_startup, RelOptInfo::consider_startup, lfirst, NIL, Path::param_info, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER2, PATHKEYS_EQUAL, RelOptInfo::pathlist, Path::startup_cost, STD_FUZZ_FACTOR, and Path::total_cost.

Referenced by add_partial_path_precheck(), try_hashjoin_path(), try_mergejoin_path(), and try_nestloop_path().

◆ adjust_limit_rows_costs()

void adjust_limit_rows_costs ( double *  rows,
Cost startup_cost,
Cost total_cost,
int64  offset_est,
int64  count_est 
)

Definition at line 3791 of file pathnode.c.

3796 {
3797  double input_rows = *rows;
3798  Cost input_startup_cost = *startup_cost;
3799  Cost input_total_cost = *total_cost;
3800 
3801  if (offset_est != 0)
3802  {
3803  double offset_rows;
3804 
3805  if (offset_est > 0)
3806  offset_rows = (double) offset_est;
3807  else
3808  offset_rows = clamp_row_est(input_rows * 0.10);
3809  if (offset_rows > *rows)
3810  offset_rows = *rows;
3811  if (input_rows > 0)
3812  *startup_cost +=
3813  (input_total_cost - input_startup_cost)
3814  * offset_rows / input_rows;
3815  *rows -= offset_rows;
3816  if (*rows < 1)
3817  *rows = 1;
3818  }
3819 
3820  if (count_est != 0)
3821  {
3822  double count_rows;
3823 
3824  if (count_est > 0)
3825  count_rows = (double) count_est;
3826  else
3827  count_rows = clamp_row_est(input_rows * 0.10);
3828  if (count_rows > *rows)
3829  count_rows = *rows;
3830  if (input_rows > 0)
3831  *total_cost = *startup_cost +
3832  (input_total_cost - input_startup_cost)
3833  * count_rows / input_rows;
3834  *rows = count_rows;
3835  if (*rows < 1)
3836  *rows = 1;
3837  }
3838 }
double clamp_row_est(double nrows)
Definition: costsize.c:201
double Cost
Definition: nodes.h:707

References clamp_row_est().

Referenced by create_limit_path(), and estimate_path_cost_size().

◆ apply_projection_to_path()

Path* apply_projection_to_path ( PlannerInfo root,
RelOptInfo rel,
Path path,
PathTarget target 
)

Definition at line 2735 of file pathnode.c.

2739 {
2740  QualCost oldcost;
2741 
2742  /*
2743  * If given path can't project, we might need a Result node, so make a
2744  * separate ProjectionPath.
2745  */
2746  if (!is_projection_capable_path(path))
2747  return (Path *) create_projection_path(root, rel, path, target);
2748 
2749  /*
2750  * We can just jam the desired tlist into the existing path, being sure to
2751  * update its cost estimates appropriately.
2752  */
2753  oldcost = path->pathtarget->cost;
2754  path->pathtarget = target;
2755 
2756  path->startup_cost += target->cost.startup - oldcost.startup;
2757  path->total_cost += target->cost.startup - oldcost.startup +
2758  (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
2759 
2760  /*
2761  * If the path happens to be a Gather or GatherMerge path, we'd like to
2762  * arrange for the subpath to return the required target list so that
2763  * workers can help project. But if there is something that is not
2764  * parallel-safe in the target expressions, then we can't.
2765  */
2766  if ((IsA(path, GatherPath) || IsA(path, GatherMergePath)) &&
2767  is_parallel_safe(root, (Node *) target->exprs))
2768  {
2769  /*
2770  * We always use create_projection_path here, even if the subpath is
2771  * projection-capable, so as to avoid modifying the subpath in place.
2772  * It seems unlikely at present that there could be any other
2773  * references to the subpath, but better safe than sorry.
2774  *
2775  * Note that we don't change the parallel path's cost estimates; it
2776  * might be appropriate to do so, to reflect the fact that the bulk of
2777  * the target evaluation will happen in workers.
2778  */
2779  if (IsA(path, GatherPath))
2780  {
2781  GatherPath *gpath = (GatherPath *) path;
2782 
2783  gpath->subpath = (Path *)
2785  gpath->subpath->parent,
2786  gpath->subpath,
2787  target);
2788  }
2789  else
2790  {
2791  GatherMergePath *gmpath = (GatherMergePath *) path;
2792 
2793  gmpath->subpath = (Path *)
2795  gmpath->subpath->parent,
2796  gmpath->subpath,
2797  target);
2798  }
2799  }
2800  else if (path->parallel_safe &&
2801  !is_parallel_safe(root, (Node *) target->exprs))
2802  {
2803  /*
2804  * We're inserting a parallel-restricted target list into a path
2805  * currently marked parallel-safe, so we have to mark it as no longer
2806  * safe.
2807  */
2808  path->parallel_safe = false;
2809  }
2810 
2811  return path;
2812 }
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition: clauses.c:683
bool is_projection_capable_path(Path *path)
Definition: createplan.c:7139
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition: pathnode.c:2627
Path * subpath
Definition: pathnodes.h:1574
Definition: nodes.h:574
List * exprs
Definition: pathnodes.h:1122
QualCost cost
Definition: pathnodes.h:1124
RelOptInfo * parent
Definition: pathnodes.h:1194
PathTarget * pathtarget
Definition: pathnodes.h:1195
Cost per_tuple
Definition: pathnodes.h:46
Cost startup
Definition: pathnodes.h:45

References PathTarget::cost, create_projection_path(), PathTarget::exprs, if(), is_parallel_safe(), is_projection_capable_path(), IsA, Path::parallel_safe, Path::parent, Path::pathtarget, QualCost::per_tuple, Path::rows, QualCost::startup, Path::startup_cost, GatherPath::subpath, GatherMergePath::subpath, and Path::total_cost.

Referenced by adjust_paths_for_srfs(), build_minmax_path(), create_ordered_paths(), and recurse_set_operations().

◆ build_child_join_rel()

RelOptInfo* build_child_join_rel ( PlannerInfo root,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
RelOptInfo parent_joinrel,
List restrictlist,
SpecialJoinInfo sjinfo,
JoinType  jointype 
)

Definition at line 786 of file relnode.c.

790 {
791  RelOptInfo *joinrel = makeNode(RelOptInfo);
792  AppendRelInfo **appinfos;
793  int nappinfos;
794 
795  /* Only joins between "other" relations land here. */
796  Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
797 
798  /* The parent joinrel should have consider_partitionwise_join set. */
799  Assert(parent_joinrel->consider_partitionwise_join);
800 
801  joinrel->reloptkind = RELOPT_OTHER_JOINREL;
802  joinrel->relids = bms_union(outer_rel->relids, inner_rel->relids);
803  joinrel->rows = 0;
804  /* cheap startup cost is interesting iff not all tuples to be retrieved */
805  joinrel->consider_startup = (root->tuple_fraction > 0);
806  joinrel->consider_param_startup = false;
807  joinrel->consider_parallel = false;
808  joinrel->reltarget = create_empty_pathtarget();
809  joinrel->pathlist = NIL;
810  joinrel->ppilist = NIL;
811  joinrel->partial_pathlist = NIL;
812  joinrel->cheapest_startup_path = NULL;
813  joinrel->cheapest_total_path = NULL;
814  joinrel->cheapest_unique_path = NULL;
816  joinrel->direct_lateral_relids = NULL;
817  joinrel->lateral_relids = NULL;
818  joinrel->relid = 0; /* indicates not a baserel */
819  joinrel->rtekind = RTE_JOIN;
820  joinrel->min_attr = 0;
821  joinrel->max_attr = 0;
822  joinrel->attr_needed = NULL;
823  joinrel->attr_widths = NULL;
824  joinrel->lateral_vars = NIL;
825  joinrel->lateral_referencers = NULL;
826  joinrel->indexlist = NIL;
827  joinrel->pages = 0;
828  joinrel->tuples = 0;
829  joinrel->allvisfrac = 0;
830  joinrel->eclass_indexes = NULL;
831  joinrel->subroot = NULL;
832  joinrel->subplan_params = NIL;
833  joinrel->amflags = 0;
834  joinrel->serverid = InvalidOid;
835  joinrel->userid = InvalidOid;
836  joinrel->useridiscurrent = false;
837  joinrel->fdwroutine = NULL;
838  joinrel->fdw_private = NULL;
839  joinrel->baserestrictinfo = NIL;
840  joinrel->baserestrictcost.startup = 0;
841  joinrel->baserestrictcost.per_tuple = 0;
842  joinrel->joininfo = NIL;
843  joinrel->has_eclass_joins = false;
844  joinrel->consider_partitionwise_join = false; /* might get changed later */
845  joinrel->top_parent_relids = NULL;
846  joinrel->part_scheme = NULL;
847  joinrel->nparts = -1;
848  joinrel->boundinfo = NULL;
849  joinrel->partbounds_merged = false;
850  joinrel->partition_qual = NIL;
851  joinrel->part_rels = NULL;
852  joinrel->live_parts = NULL;
853  joinrel->all_partrels = NULL;
854  joinrel->partexprs = NULL;
855  joinrel->nullable_partexprs = NULL;
856 
857  joinrel->top_parent_relids = bms_union(outer_rel->top_parent_relids,
858  inner_rel->top_parent_relids);
859 
860  /* Compute information relevant to foreign relations. */
861  set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
862 
863  /* Compute information needed for mapping Vars to the child rel */
864  appinfos = find_appinfos_by_relids(root, joinrel->relids, &nappinfos);
865 
866  /* Set up reltarget struct */
867  build_child_join_reltarget(root, parent_joinrel, joinrel,
868  nappinfos, appinfos);
869 
870  /* Construct joininfo list. */
871  joinrel->joininfo = (List *) adjust_appendrel_attrs(root,
872  (Node *) parent_joinrel->joininfo,
873  nappinfos,
874  appinfos);
875 
876  /*
877  * Lateral relids referred in child join will be same as that referred in
878  * the parent relation.
879  */
880  joinrel->direct_lateral_relids = (Relids) bms_copy(parent_joinrel->direct_lateral_relids);
881  joinrel->lateral_relids = (Relids) bms_copy(parent_joinrel->lateral_relids);
882 
883  /*
884  * If the parent joinrel has pending equivalence classes, so does the
885  * child.
886  */
887  joinrel->has_eclass_joins = parent_joinrel->has_eclass_joins;
888 
889  /* Is the join between partitions itself partitioned? */
890  build_joinrel_partition_info(joinrel, outer_rel, inner_rel, restrictlist,
891  jointype);
892 
893  /* Child joinrel is parallel safe if parent is parallel safe. */
894  joinrel->consider_parallel = parent_joinrel->consider_parallel;
895 
896  /* Set estimates of the child-joinrel's size. */
897  set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
898  sjinfo, restrictlist);
899 
900  /* We build the join only once. */
901  Assert(!find_join_rel(root, joinrel->relids));
902 
903  /* Add the relation to the PlannerInfo. */
904  add_join_rel(root, joinrel);
905 
906  /*
907  * We might need EquivalenceClass members corresponding to the child join,
908  * so that we can represent sort pathkeys for it. As with children of
909  * baserels, we shouldn't need this unless there are relevant eclass joins
910  * (implying that a merge join might be possible) or pathkeys to sort by.
911  */
912  if (joinrel->has_eclass_joins || has_useful_pathkeys(root, parent_joinrel))
914  nappinfos, appinfos,
915  parent_joinrel, joinrel);
916 
917  pfree(appinfos);
918 
919  return joinrel;
920 }
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition: appendinfo.c:715
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:195
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition: costsize.c:5368
void add_child_join_rel_equivalences(PlannerInfo *root, int nappinfos, AppendRelInfo **appinfos, RelOptInfo *parent_joinrel, RelOptInfo *child_joinrel)
Definition: equivclass.c:2678
#define makeNode(_type_)
Definition: nodes.h:621
@ RTE_JOIN
Definition: parsenodes.h:1000
bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel)
Definition: pathkeys.c:2484
Bitmapset * Relids
Definition: pathnodes.h:28
@ RELOPT_OTHER_JOINREL
Definition: pathnodes.h:645
#define IS_OTHER_REL(rel)
Definition: pathnodes.h:670
#define InvalidOid
Definition: postgres_ext.h:36
RelOptInfo * find_join_rel(PlannerInfo *root, Relids relids)
Definition: relnode.c:439
static void build_child_join_reltarget(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, int nappinfos, AppendRelInfo **appinfos)
Definition: relnode.c:2031
static void set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:502
static void build_joinrel_partition_info(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, List *restrictlist, JoinType jointype)
Definition: relnode.c:1648
static void add_join_rel(PlannerInfo *root, RelOptInfo *joinrel)
Definition: relnode.c:540
Selectivity tuple_fraction
Definition: pathnodes.h:341
List * baserestrictinfo
Definition: pathnodes.h:746
List * subplan_params
Definition: pathnodes.h:727
List ** partexprs
Definition: pathnodes.h:775
List * ppilist
Definition: pathnodes.h:697
void * fdw_private
Definition: pathnodes.h:738
bool useridiscurrent
Definition: pathnodes.h:735
uint32 amflags
Definition: pathnodes.h:729
List * joininfo
Definition: pathnodes.h:750
List * partition_qual
Definition: pathnodes.h:768
Relids relids
Definition: pathnodes.h:682
struct PathTarget * reltarget
Definition: pathnodes.h:693
int32 * attr_widths
Definition: pathnodes.h:716
Relids * attr_needed
Definition: pathnodes.h:715
Index relid
Definition: pathnodes.h:710
struct FdwRoutine * fdwroutine
Definition: pathnodes.h:737
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:765
PartitionScheme part_scheme
Definition: pathnodes.h:761
List * lateral_vars
Definition: pathnodes.h:717
int nparts
Definition: pathnodes.h:762
Cardinality tuples
Definition: pathnodes.h:722
Relids top_parent_relids
Definition: pathnodes.h:757
bool partbounds_merged
Definition: pathnodes.h:766
BlockNumber pages
Definition: pathnodes.h:721
Relids lateral_relids
Definition: pathnodes.h:707
List * cheapest_parameterized_paths
Definition: pathnodes.h:702
RelOptKind reloptkind
Definition: pathnodes.h:679
List * indexlist
Definition: pathnodes.h:719
struct Path * cheapest_unique_path
Definition: pathnodes.h:701
Relids lateral_referencers
Definition: pathnodes.h:718
struct Path * cheapest_startup_path
Definition: pathnodes.h:699
QualCost baserestrictcost
Definition: pathnodes.h:747
struct Path * cheapest_total_path
Definition: pathnodes.h:700
Oid userid
Definition: pathnodes.h:734
Bitmapset * eclass_indexes
Definition: pathnodes.h:724
Relids all_partrels
Definition: pathnodes.h:774
struct RelOptInfo ** part_rels
Definition: pathnodes.h:769
Relids direct_lateral_relids
Definition: pathnodes.h:706
bool has_eclass_joins
Definition: pathnodes.h:752
Oid serverid
Definition: pathnodes.h:733
List ** nullable_partexprs
Definition: pathnodes.h:776
Bitmapset * live_parts
Definition: pathnodes.h:771
bool consider_partitionwise_join
Definition: pathnodes.h:755
PlannerInfo * subroot
Definition: pathnodes.h:726
AttrNumber max_attr
Definition: pathnodes.h:714
double allvisfrac
Definition: pathnodes.h:723
Cardinality rows
Definition: pathnodes.h:685
AttrNumber min_attr
Definition: pathnodes.h:713
RTEKind rtekind
Definition: pathnodes.h:712
PathTarget * create_empty_pathtarget(void)
Definition: tlist.c:670

References add_child_join_rel_equivalences(), add_join_rel(), adjust_appendrel_attrs(), RelOptInfo::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, Assert(), RelOptInfo::attr_needed, RelOptInfo::attr_widths, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_copy(), bms_union(), RelOptInfo::boundinfo, build_child_join_reltarget(), build_joinrel_partition_info(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, RelOptInfo::consider_parallel, RelOptInfo::consider_param_startup, RelOptInfo::consider_partitionwise_join, RelOptInfo::consider_startup, create_empty_pathtarget(), RelOptInfo::direct_lateral_relids, RelOptInfo::eclass_indexes, RelOptInfo::fdw_private, RelOptInfo::fdwroutine, find_appinfos_by_relids(), find_join_rel(), RelOptInfo::has_eclass_joins, has_useful_pathkeys(), RelOptInfo::indexlist, InvalidOid, IS_OTHER_REL, RelOptInfo::joininfo, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, RelOptInfo::live_parts, makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, NIL, RelOptInfo::nparts, RelOptInfo::nullable_partexprs, RelOptInfo::pages, RelOptInfo::part_rels, RelOptInfo::part_scheme, RelOptInfo::partbounds_merged, RelOptInfo::partexprs, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, pfree(), RelOptInfo::ppilist, RelOptInfo::relid, RelOptInfo::relids, RELOPT_OTHER_JOINREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, RelOptInfo::rows, RTE_JOIN, RelOptInfo::rtekind, RelOptInfo::serverid, set_foreign_rel_properties(), set_joinrel_size_estimates(), QualCost::startup, RelOptInfo::subplan_params, RelOptInfo::subroot, RelOptInfo::top_parent_relids, PlannerInfo::tuple_fraction, RelOptInfo::tuples, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by try_partitionwise_join().

◆ build_join_rel()

RelOptInfo* build_join_rel ( PlannerInfo root,
Relids  joinrelids,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
SpecialJoinInfo sjinfo,
List **  restrictlist_ptr 
)

Definition at line 577 of file relnode.c.

583 {
584  RelOptInfo *joinrel;
585  List *restrictlist;
586 
587  /* This function should be used only for join between parents. */
588  Assert(!IS_OTHER_REL(outer_rel) && !IS_OTHER_REL(inner_rel));
589 
590  /*
591  * See if we already have a joinrel for this set of base rels.
592  */
593  joinrel = find_join_rel(root, joinrelids);
594 
595  if (joinrel)
596  {
597  /*
598  * Yes, so we only need to figure the restrictlist for this particular
599  * pair of component relations.
600  */
601  if (restrictlist_ptr)
602  *restrictlist_ptr = build_joinrel_restrictlist(root,
603  joinrel,
604  outer_rel,
605  inner_rel);
606  return joinrel;
607  }
608 
609  /*
610  * Nope, so make one.
611  */
612  joinrel = makeNode(RelOptInfo);
613  joinrel->reloptkind = RELOPT_JOINREL;
614  joinrel->relids = bms_copy(joinrelids);
615  joinrel->rows = 0;
616  /* cheap startup cost is interesting iff not all tuples to be retrieved */
617  joinrel->consider_startup = (root->tuple_fraction > 0);
618  joinrel->consider_param_startup = false;
619  joinrel->consider_parallel = false;
620  joinrel->reltarget = create_empty_pathtarget();
621  joinrel->pathlist = NIL;
622  joinrel->ppilist = NIL;
623  joinrel->partial_pathlist = NIL;
624  joinrel->cheapest_startup_path = NULL;
625  joinrel->cheapest_total_path = NULL;
626  joinrel->cheapest_unique_path = NULL;
628  /* init direct_lateral_relids from children; we'll finish it up below */
629  joinrel->direct_lateral_relids =
630  bms_union(outer_rel->direct_lateral_relids,
631  inner_rel->direct_lateral_relids);
632  joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids,
633  outer_rel, inner_rel);
634  joinrel->relid = 0; /* indicates not a baserel */
635  joinrel->rtekind = RTE_JOIN;
636  joinrel->min_attr = 0;
637  joinrel->max_attr = 0;
638  joinrel->attr_needed = NULL;
639  joinrel->attr_widths = NULL;
640  joinrel->lateral_vars = NIL;
641  joinrel->lateral_referencers = NULL;
642  joinrel->indexlist = NIL;
643  joinrel->statlist = NIL;
644  joinrel->pages = 0;
645  joinrel->tuples = 0;
646  joinrel->allvisfrac = 0;
647  joinrel->eclass_indexes = NULL;
648  joinrel->subroot = NULL;
649  joinrel->subplan_params = NIL;
650  joinrel->rel_parallel_workers = -1;
651  joinrel->amflags = 0;
652  joinrel->serverid = InvalidOid;
653  joinrel->userid = InvalidOid;
654  joinrel->useridiscurrent = false;
655  joinrel->fdwroutine = NULL;
656  joinrel->fdw_private = NULL;
657  joinrel->unique_for_rels = NIL;
658  joinrel->non_unique_for_rels = NIL;
659  joinrel->baserestrictinfo = NIL;
660  joinrel->baserestrictcost.startup = 0;
661  joinrel->baserestrictcost.per_tuple = 0;
662  joinrel->baserestrict_min_security = UINT_MAX;
663  joinrel->joininfo = NIL;
664  joinrel->has_eclass_joins = false;
665  joinrel->consider_partitionwise_join = false; /* might get changed later */
666  joinrel->top_parent_relids = NULL;
667  joinrel->part_scheme = NULL;
668  joinrel->nparts = -1;
669  joinrel->boundinfo = NULL;
670  joinrel->partbounds_merged = false;
671  joinrel->partition_qual = NIL;
672  joinrel->part_rels = NULL;
673  joinrel->live_parts = NULL;
674  joinrel->all_partrels = NULL;
675  joinrel->partexprs = NULL;
676  joinrel->nullable_partexprs = NULL;
677 
678  /* Compute information relevant to the foreign relations. */
679  set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
680 
681  /*
682  * Create a new tlist containing just the vars that need to be output from
683  * this join (ie, are needed for higher joinclauses or final output).
684  *
685  * NOTE: the tlist order for a join rel will depend on which pair of outer
686  * and inner rels we first try to build it from. But the contents should
687  * be the same regardless.
688  */
689  build_joinrel_tlist(root, joinrel, outer_rel);
690  build_joinrel_tlist(root, joinrel, inner_rel);
691  add_placeholders_to_joinrel(root, joinrel, outer_rel, inner_rel);
692 
693  /*
694  * add_placeholders_to_joinrel also took care of adding the ph_lateral
695  * sets of any PlaceHolderVars computed here to direct_lateral_relids, so
696  * now we can finish computing that. This is much like the computation of
697  * the transitively-closed lateral_relids in min_join_parameterization,
698  * except that here we *do* have to consider the added PHVs.
699  */
700  joinrel->direct_lateral_relids =
701  bms_del_members(joinrel->direct_lateral_relids, joinrel->relids);
702  if (bms_is_empty(joinrel->direct_lateral_relids))
703  joinrel->direct_lateral_relids = NULL;
704 
705  /*
706  * Construct restrict and join clause lists for the new joinrel. (The
707  * caller might or might not need the restrictlist, but I need it anyway
708  * for set_joinrel_size_estimates().)
709  */
710  restrictlist = build_joinrel_restrictlist(root, joinrel,
711  outer_rel, inner_rel);
712  if (restrictlist_ptr)
713  *restrictlist_ptr = restrictlist;
714  build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
715 
716  /*
717  * This is also the right place to check whether the joinrel has any
718  * pending EquivalenceClass joins.
719  */
720  joinrel->has_eclass_joins = has_relevant_eclass_joinclause(root, joinrel);
721 
722  /* Store the partition information. */
723  build_joinrel_partition_info(joinrel, outer_rel, inner_rel, restrictlist,
724  sjinfo->jointype);
725 
726  /*
727  * Set estimates of the joinrel's size.
728  */
729  set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
730  sjinfo, restrictlist);
731 
732  /*
733  * Set the consider_parallel flag if this joinrel could potentially be
734  * scanned within a parallel worker. If this flag is false for either
735  * inner_rel or outer_rel, then it must be false for the joinrel also.
736  * Even if both are true, there might be parallel-restricted expressions
737  * in the targetlist or quals.
738  *
739  * Note that if there are more than two rels in this relation, they could
740  * be divided between inner_rel and outer_rel in any arbitrary way. We
741  * assume this doesn't matter, because we should hit all the same baserels
742  * and joinclauses while building up to this joinrel no matter which we
743  * take; therefore, we should make the same decision here however we get
744  * here.
745  */
746  if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
747  is_parallel_safe(root, (Node *) restrictlist) &&
748  is_parallel_safe(root, (Node *) joinrel->reltarget->exprs))
749  joinrel->consider_parallel = true;
750 
751  /* Add the joinrel to the PlannerInfo. */
752  add_join_rel(root, joinrel);
753 
754  /*
755  * Also, if dynamic-programming join search is active, add the new joinrel
756  * to the appropriate sublist. Note: you might think the Assert on number
757  * of members should be for equality, but some of the level 1 rels might
758  * have been joinrels already, so we can only assert <=.
759  */
760  if (root->join_rel_level)
761  {
762  Assert(root->join_cur_level > 0);
763  Assert(root->join_cur_level <= bms_num_members(joinrel->relids));
764  root->join_rel_level[root->join_cur_level] =
765  lappend(root->join_rel_level[root->join_cur_level], joinrel);
766  }
767 
768  return joinrel;
769 }
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:648
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:930
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:703
bool has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
Definition: equivclass.c:3029
List * lappend(List *list, void *datum)
Definition: list.c:336
@ RELOPT_JOINREL
Definition: pathnodes.h:643
void add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: placeholder.c:413
Relids min_join_parameterization(PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:931
static List * build_joinrel_restrictlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:1076
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel)
Definition: relnode.c:974
static void build_joinrel_joinlist(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:1106
List ** join_rel_level
Definition: pathnodes.h:239
int join_cur_level
Definition: pathnodes.h:240
List * statlist
Definition: pathnodes.h:720
List * unique_for_rels
Definition: pathnodes.h:741
List * non_unique_for_rels
Definition: pathnodes.h:743
int rel_parallel_workers
Definition: pathnodes.h:728
Index baserestrict_min_security
Definition: pathnodes.h:748
JoinType jointype
Definition: pathnodes.h:2276

References add_join_rel(), add_placeholders_to_joinrel(), RelOptInfo::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, Assert(), RelOptInfo::attr_needed, RelOptInfo::attr_widths, RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_copy(), bms_del_members(), bms_is_empty(), bms_num_members(), bms_union(), RelOptInfo::boundinfo, build_joinrel_joinlist(), build_joinrel_partition_info(), build_joinrel_restrictlist(), build_joinrel_tlist(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, RelOptInfo::consider_parallel, RelOptInfo::consider_param_startup, RelOptInfo::consider_partitionwise_join, RelOptInfo::consider_startup, create_empty_pathtarget(), RelOptInfo::direct_lateral_relids, RelOptInfo::eclass_indexes, PathTarget::exprs, RelOptInfo::fdw_private, RelOptInfo::fdwroutine, find_join_rel(), RelOptInfo::has_eclass_joins, has_relevant_eclass_joinclause(), RelOptInfo::indexlist, InvalidOid, IS_OTHER_REL, is_parallel_safe(), PlannerInfo::join_cur_level, PlannerInfo::join_rel_level, RelOptInfo::joininfo, SpecialJoinInfo::jointype, lappend(), RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, RelOptInfo::live_parts, makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, min_join_parameterization(), NIL, RelOptInfo::non_unique_for_rels, RelOptInfo::nparts, RelOptInfo::nullable_partexprs, RelOptInfo::pages, RelOptInfo::part_rels, RelOptInfo::part_scheme, RelOptInfo::partbounds_merged, RelOptInfo::partexprs, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::ppilist, RelOptInfo::rel_parallel_workers, RelOptInfo::relid, RelOptInfo::relids, RELOPT_JOINREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, RelOptInfo::rows, RTE_JOIN, RelOptInfo::rtekind, RelOptInfo::serverid, set_foreign_rel_properties(), set_joinrel_size_estimates(), QualCost::startup, RelOptInfo::statlist, RelOptInfo::subplan_params, RelOptInfo::subroot, RelOptInfo::top_parent_relids, PlannerInfo::tuple_fraction, RelOptInfo::tuples, RelOptInfo::unique_for_rels, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by make_join_rel().

◆ build_simple_rel()

RelOptInfo* build_simple_rel ( PlannerInfo root,
int  relid,
RelOptInfo parent 
)

Definition at line 194 of file relnode.c.

195 {
196  RelOptInfo *rel;
197  RangeTblEntry *rte;
198 
199  /* Rel should not exist already */
200  Assert(relid > 0 && relid < root->simple_rel_array_size);
201  if (root->simple_rel_array[relid] != NULL)
202  elog(ERROR, "rel %d already exists", relid);
203 
204  /* Fetch RTE for relation */
205  rte = root->simple_rte_array[relid];
206  Assert(rte != NULL);
207 
208  rel = makeNode(RelOptInfo);
210  rel->relids = bms_make_singleton(relid);
211  rel->rows = 0;
212  /* cheap startup cost is interesting iff not all tuples to be retrieved */
213  rel->consider_startup = (root->tuple_fraction > 0);
214  rel->consider_param_startup = false; /* might get changed later */
215  rel->consider_parallel = false; /* might get changed later */
217  rel->pathlist = NIL;
218  rel->ppilist = NIL;
219  rel->partial_pathlist = NIL;
220  rel->cheapest_startup_path = NULL;
221  rel->cheapest_total_path = NULL;
222  rel->cheapest_unique_path = NULL;
224  rel->relid = relid;
225  rel->rtekind = rte->rtekind;
226  /* min_attr, max_attr, attr_needed, attr_widths are set below */
227  rel->lateral_vars = NIL;
228  rel->indexlist = NIL;
229  rel->statlist = NIL;
230  rel->pages = 0;
231  rel->tuples = 0;
232  rel->allvisfrac = 0;
233  rel->eclass_indexes = NULL;
234  rel->subroot = NULL;
235  rel->subplan_params = NIL;
236  rel->rel_parallel_workers = -1; /* set up in get_relation_info */
237  rel->amflags = 0;
238  rel->serverid = InvalidOid;
239  rel->userid = rte->checkAsUser;
240  rel->useridiscurrent = false;
241  rel->fdwroutine = NULL;
242  rel->fdw_private = NULL;
243  rel->unique_for_rels = NIL;
244  rel->non_unique_for_rels = NIL;
245  rel->baserestrictinfo = NIL;
246  rel->baserestrictcost.startup = 0;
247  rel->baserestrictcost.per_tuple = 0;
248  rel->baserestrict_min_security = UINT_MAX;
249  rel->joininfo = NIL;
250  rel->has_eclass_joins = false;
251  rel->consider_partitionwise_join = false; /* might get changed later */
252  rel->part_scheme = NULL;
253  rel->nparts = -1;
254  rel->boundinfo = NULL;
255  rel->partbounds_merged = false;
256  rel->partition_qual = NIL;
257  rel->part_rels = NULL;
258  rel->live_parts = NULL;
259  rel->all_partrels = NULL;
260  rel->partexprs = NULL;
261  rel->nullable_partexprs = NULL;
262 
263  /*
264  * Pass assorted information down the inheritance hierarchy.
265  */
266  if (parent)
267  {
268  /*
269  * Each direct or indirect child wants to know the relids of its
270  * topmost parent.
271  */
272  if (parent->top_parent_relids)
273  rel->top_parent_relids = parent->top_parent_relids;
274  else
275  rel->top_parent_relids = bms_copy(parent->relids);
276 
277  /*
278  * Also propagate lateral-reference information from appendrel parent
279  * rels to their child rels. We intentionally give each child rel the
280  * same minimum parameterization, even though it's quite possible that
281  * some don't reference all the lateral rels. This is because any
282  * append path for the parent will have to have the same
283  * parameterization for every child anyway, and there's no value in
284  * forcing extra reparameterize_path() calls. Similarly, a lateral
285  * reference to the parent prevents use of otherwise-movable join rels
286  * for each child.
287  *
288  * It's possible for child rels to have their own children, in which
289  * case the topmost parent's lateral info propagates all the way down.
290  */
292  rel->lateral_relids = parent->lateral_relids;
294  }
295  else
296  {
297  rel->top_parent_relids = NULL;
298  rel->direct_lateral_relids = NULL;
299  rel->lateral_relids = NULL;
300  rel->lateral_referencers = NULL;
301  }
302 
303  /* Check type of rtable entry */
304  switch (rte->rtekind)
305  {
306  case RTE_RELATION:
307  /* Table --- retrieve statistics from the system catalogs */
308  get_relation_info(root, rte->relid, rte->inh, rel);
309  break;
310  case RTE_SUBQUERY:
311  case RTE_FUNCTION:
312  case RTE_TABLEFUNC:
313  case RTE_VALUES:
314  case RTE_CTE:
315  case RTE_NAMEDTUPLESTORE:
316 
317  /*
318  * Subquery, function, tablefunc, values list, CTE, or ENR --- set
319  * up attr range and arrays
320  *
321  * Note: 0 is included in range to support whole-row Vars
322  */
323  rel->min_attr = 0;
324  rel->max_attr = list_length(rte->eref->colnames);
325  rel->attr_needed = (Relids *)
326  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
327  rel->attr_widths = (int32 *)
328  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
329  break;
330  case RTE_RESULT:
331  /* RTE_RESULT has no columns, nor could it have whole-row Var */
332  rel->min_attr = 0;
333  rel->max_attr = -1;
334  rel->attr_needed = NULL;
335  rel->attr_widths = NULL;
336  break;
337  default:
338  elog(ERROR, "unrecognized RTE kind: %d",
339  (int) rte->rtekind);
340  break;
341  }
342 
343  /*
344  * Copy the parent's quals to the child, with appropriate substitution of
345  * variables. If any constant false or NULL clauses turn up, we can mark
346  * the child as dummy right away. (We must do this immediately so that
347  * pruning works correctly when recursing in expand_partitioned_rtentry.)
348  */
349  if (parent)
350  {
351  AppendRelInfo *appinfo = root->append_rel_array[relid];
352 
353  Assert(appinfo != NULL);
354  if (!apply_child_basequals(root, parent, rel, rte, appinfo))
355  {
356  /*
357  * Some restriction clause reduced to constant FALSE or NULL after
358  * substitution, so this child need not be scanned.
359  */
360  mark_dummy_rel(rel);
361  }
362  }
363 
364  /* Save the finished struct in the query's simple_rel_array */
365  root->simple_rel_array[relid] = rel;
366 
367  return rel;
368 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:186
signed int int32
Definition: c.h:429
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
bool apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, RangeTblEntry *childRTE, AppendRelInfo *appinfo)
Definition: inherit.c:754
void mark_dummy_rel(RelOptInfo *rel)
Definition: joinrels.c:1261
void * palloc0(Size size)
Definition: mcxt.c:1099
@ RTE_CTE
Definition: parsenodes.h:1004
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1005
@ RTE_VALUES
Definition: parsenodes.h:1003
@ RTE_SUBQUERY
Definition: parsenodes.h:999
@ RTE_RESULT
Definition: parsenodes.h:1006
@ RTE_FUNCTION
Definition: parsenodes.h:1001
@ RTE_TABLEFUNC
Definition: parsenodes.h:1002
@ RTE_RELATION
Definition: parsenodes.h:998
@ RELOPT_BASEREL
Definition: pathnodes.h:642
@ RELOPT_OTHER_MEMBER_REL
Definition: pathnodes.h:644
static int list_length(const List *l)
Definition: pg_list.h:149
void get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, RelOptInfo *rel)
Definition: plancat.c:114
List * colnames
Definition: primnodes.h:43
struct AppendRelInfo ** append_rel_array
Definition: pathnodes.h:202
struct RelOptInfo ** simple_rel_array
Definition: pathnodes.h:186
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:194
Alias * eref
Definition: parsenodes.h:1161
RTEKind rtekind
Definition: parsenodes.h:1015

References RelOptInfo::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, PlannerInfo::append_rel_array, apply_child_basequals(), Assert(), RelOptInfo::attr_needed, RelOptInfo::attr_widths, RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_copy(), bms_make_singleton(), RelOptInfo::boundinfo, RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, RangeTblEntry::checkAsUser, Alias::colnames, RelOptInfo::consider_parallel, RelOptInfo::consider_param_startup, RelOptInfo::consider_partitionwise_join, RelOptInfo::consider_startup, create_empty_pathtarget(), RelOptInfo::direct_lateral_relids, RelOptInfo::eclass_indexes, elog, RangeTblEntry::eref, ERROR, RelOptInfo::fdw_private, RelOptInfo::fdwroutine, get_relation_info(), RelOptInfo::has_eclass_joins, RelOptInfo::indexlist, RangeTblEntry::inh, InvalidOid, RelOptInfo::joininfo, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, list_length(), RelOptInfo::live_parts, makeNode, mark_dummy_rel(), RelOptInfo::max_attr, RelOptInfo::min_attr, NIL, RelOptInfo::non_unique_for_rels, RelOptInfo::nparts, RelOptInfo::nullable_partexprs, RelOptInfo::pages, palloc0(), RelOptInfo::part_rels, RelOptInfo::part_scheme, RelOptInfo::partbounds_merged, RelOptInfo::partexprs, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::ppilist, RelOptInfo::rel_parallel_workers, RangeTblEntry::relid, RelOptInfo::relid, RelOptInfo::relids, RELOPT_BASEREL, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, RelOptInfo::reltarget, RelOptInfo::rows, RTE_CTE, RTE_FUNCTION, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RelOptInfo::rtekind, RelOptInfo::serverid, PlannerInfo::simple_rel_array, PlannerInfo::simple_rte_array, QualCost::startup, RelOptInfo::statlist, RelOptInfo::subplan_params, RelOptInfo::subroot, RelOptInfo::top_parent_relids, PlannerInfo::tuple_fraction, RelOptInfo::tuples, RelOptInfo::unique_for_rels, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by add_base_rels_to_query(), expand_appendrel_subquery(), expand_inherited_rtentry(), expand_partitioned_rtentry(), plan_cluster_use_sort(), plan_create_index_workers(), query_planner(), and recurse_set_operations().

◆ calc_nestloop_required_outer()

Relids calc_nestloop_required_outer ( Relids  outerrelids,
Relids  outer_paramrels,
Relids  innerrelids,
Relids  inner_paramrels 
)

Definition at line 2341 of file pathnode.c.

2345 {
2346  Relids required_outer;
2347 
2348  /* inner_path can require rels from outer path, but not vice versa */
2349  Assert(!bms_overlap(outer_paramrels, innerrelids));
2350  /* easy case if inner path is not parameterized */
2351  if (!inner_paramrels)
2352  return bms_copy(outer_paramrels);
2353  /* else, form the union ... */
2354  required_outer = bms_union(outer_paramrels, inner_paramrels);
2355  /* ... and remove any mention of now-satisfied outer rels */
2356  required_outer = bms_del_members(required_outer,
2357  outerrelids);
2358  /* maintain invariant that required_outer is exactly NULL if empty */
2359  if (bms_is_empty(required_outer))
2360  {
2361  bms_free(required_outer);
2362  required_outer = NULL;
2363  }
2364  return required_outer;
2365 }
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494

References Assert(), bms_copy(), bms_del_members(), bms_free(), bms_is_empty(), bms_overlap(), and bms_union().

Referenced by try_nestloop_path().

◆ calc_non_nestloop_required_outer()

Relids calc_non_nestloop_required_outer ( Path outer_path,
Path inner_path 
)

Definition at line 2374 of file pathnode.c.

2375 {
2376  Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
2377  Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
2378  Relids required_outer;
2379 
2380  /* neither path can require rels from the other */
2381  Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids));
2382  Assert(!bms_overlap(inner_paramrels, outer_path->parent->relids));
2383  /* form the union ... */
2384  required_outer = bms_union(outer_paramrels, inner_paramrels);
2385  /* we do not need an explicit test for empty; bms_union gets it right */
2386  return required_outer;
2387 }

References Assert(), bms_overlap(), bms_union(), Path::parent, PATH_REQ_OUTER, and RelOptInfo::relids.

Referenced by try_hashjoin_path(), and try_mergejoin_path().

◆ compare_fractional_path_costs()

int compare_fractional_path_costs ( Path path1,
Path path2,
double  fraction 
)

Definition at line 117 of file pathnode.c.

119 {
120  Cost cost1,
121  cost2;
122 
123  if (fraction <= 0.0 || fraction >= 1.0)
124  return compare_path_costs(path1, path2, TOTAL_COST);
125  cost1 = path1->startup_cost +
126  fraction * (path1->total_cost - path1->startup_cost);
127  cost2 = path2->startup_cost +
128  fraction * (path2->total_cost - path2->startup_cost);
129  if (cost1 < cost2)
130  return -1;
131  if (cost1 > cost2)
132  return +1;
133  return 0;
134 }
int compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
Definition: pathnode.c:71
@ TOTAL_COST
Definition: pathnodes.h:36

References compare_path_costs(), Path::startup_cost, TOTAL_COST, and Path::total_cost.

Referenced by choose_hashed_setop(), get_cheapest_fractional_path(), and get_cheapest_fractional_path_for_pathkeys().

◆ compare_path_costs()

int compare_path_costs ( Path path1,
Path path2,
CostSelector  criterion 
)

Definition at line 71 of file pathnode.c.

72 {
73  if (criterion == STARTUP_COST)
74  {
75  if (path1->startup_cost < path2->startup_cost)
76  return -1;
77  if (path1->startup_cost > path2->startup_cost)
78  return +1;
79 
80  /*
81  * If paths have the same startup cost (not at all unlikely), order
82  * them by total cost.
83  */
84  if (path1->total_cost < path2->total_cost)
85  return -1;
86  if (path1->total_cost > path2->total_cost)
87  return +1;
88  }
89  else
90  {
91  if (path1->total_cost < path2->total_cost)
92  return -1;
93  if (path1->total_cost > path2->total_cost)
94  return +1;
95 
96  /*
97  * If paths have the same total cost, order them by startup cost.
98  */
99  if (path1->startup_cost < path2->startup_cost)
100  return -1;
101  if (path1->startup_cost > path2->startup_cost)
102  return +1;
103  }
104  return 0;
105 }
@ STARTUP_COST
Definition: pathnodes.h:36

References STARTUP_COST, Path::startup_cost, and Path::total_cost.

Referenced by append_startup_cost_compare(), append_total_cost_compare(), compare_fractional_path_costs(), generate_mergejoin_paths(), get_cheapest_parameterized_child_path(), get_cheapest_path_for_pathkeys(), and set_cheapest().

◆ create_agg_path()

AggPath* create_agg_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target,
AggStrategy  aggstrategy,
AggSplit  aggsplit,
List groupClause,
List qual,
const AggClauseCosts aggcosts,
double  numGroups 
)

Definition at line 3097 of file pathnode.c.

3107 {
3108  AggPath *pathnode = makeNode(AggPath);
3109 
3110  pathnode->path.pathtype = T_Agg;
3111  pathnode->path.parent = rel;
3112  pathnode->path.pathtarget = target;
3113  /* For now, assume we are above any joins, so no parameterization */
3114  pathnode->path.param_info = NULL;
3115  pathnode->path.parallel_aware = false;
3116  pathnode->path.parallel_safe = rel->consider_parallel &&
3117  subpath->parallel_safe;
3118  pathnode->path.parallel_workers = subpath->parallel_workers;
3119  if (aggstrategy == AGG_SORTED)
3120  pathnode->path.pathkeys = subpath->pathkeys; /* preserves order */
3121  else
3122  pathnode->path.pathkeys = NIL; /* output is unordered */
3123  pathnode->subpath = subpath;
3124 
3125  pathnode->aggstrategy = aggstrategy;
3126  pathnode->aggsplit = aggsplit;
3127  pathnode->numGroups = numGroups;
3128  pathnode->transitionSpace = aggcosts ? aggcosts->transitionSpace : 0;
3129  pathnode->groupClause = groupClause;
3130  pathnode->qual = qual;
3131 
3132  cost_agg(&pathnode->path, root,
3133  aggstrategy, aggcosts,
3134  list_length(groupClause), numGroups,
3135  qual,
3136  subpath->startup_cost, subpath->total_cost,
3137  subpath->rows, subpath->pathtarget->width);
3138 
3139  /* add tlist eval cost for each output row */
3140  pathnode->path.startup_cost += target->cost.startup;
3141  pathnode->path.total_cost += target->cost.startup +
3142  target->cost.per_tuple * pathnode->path.rows;
3143 
3144  return pathnode;
3145 }
void cost_agg(Path *path, PlannerInfo *root, AggStrategy aggstrategy, const AggClauseCosts *aggcosts, int numGroupCols, double numGroups, List *quals, Cost input_startup_cost, Cost input_total_cost, double input_tuples, double input_width)
Definition: costsize.c:2919
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:241
@ AGG_SORTED
Definition: nodes.h:808
@ T_Agg
Definition: nodes.h:82
Size transitionSpace
Definition: pathnodes.h:60
Path * subpath
Definition: pathnodes.h:1784
Cardinality numGroups
Definition: pathnodes.h:1787
AggSplit aggsplit
Definition: pathnodes.h:1786
List * groupClause
Definition: pathnodes.h:1789
uint64 transitionSpace
Definition: pathnodes.h:1788
AggStrategy aggstrategy
Definition: pathnodes.h:1785
Path path
Definition: pathnodes.h:1783
List * qual
Definition: pathnodes.h:1790
NodeTag pathtype
Definition: pathnodes.h:1192
int parallel_workers
Definition: pathnodes.h:1201
bool parallel_aware
Definition: pathnodes.h:1199

References AGG_SORTED, AggPath::aggsplit, AggPath::aggstrategy, RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), AggPath::groupClause, list_length(), makeNode, NIL, AggPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, AggPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, AggPath::qual, Path::rows, QualCost::startup, Path::startup_cost, subpath(), AggPath::subpath, T_Agg, Path::total_cost, AggClauseCosts::transitionSpace, and AggPath::transitionSpace.

Referenced by add_paths_to_grouping_rel(), create_final_distinct_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), and make_union_unique().

◆ create_append_path()

AppendPath* create_append_path ( PlannerInfo root,
RelOptInfo rel,
List subpaths,
List partial_subpaths,
List pathkeys,
Relids  required_outer,
int  parallel_workers,
bool  parallel_aware,
double  rows 
)

Definition at line 1244 of file pathnode.c.

1250 {
1251  AppendPath *pathnode = makeNode(AppendPath);
1252  ListCell *l;
1253 
1254  Assert(!parallel_aware || parallel_workers > 0);
1255 
1256  pathnode->path.pathtype = T_Append;
1257  pathnode->path.parent = rel;
1258  pathnode->path.pathtarget = rel->reltarget;
1259 
1260  /*
1261  * When generating an Append path for a partitioned table, there may be
1262  * parameterized quals that are useful for run-time pruning. Hence,
1263  * compute path.param_info the same way as for any other baserel, so that
1264  * such quals will be available for make_partition_pruneinfo(). (This
1265  * would not work right for a non-baserel, ie a scan on a non-leaf child
1266  * partition, and it's not necessary anyway in that case. Must skip it if
1267  * we don't have "root", too.)
1268  */
1269  if (root && rel->reloptkind == RELOPT_BASEREL && IS_PARTITIONED_REL(rel))
1270  pathnode->path.param_info = get_baserel_parampathinfo(root,
1271  rel,
1272  required_outer);
1273  else
1275  required_outer);
1276 
1277  pathnode->path.parallel_aware = parallel_aware;
1278  pathnode->path.parallel_safe = rel->consider_parallel;
1279  pathnode->path.parallel_workers = parallel_workers;
1280  pathnode->path.pathkeys = pathkeys;
1281 
1282  /*
1283  * For parallel append, non-partial paths are sorted by descending total
1284  * costs. That way, the total time to finish all non-partial paths is
1285  * minimized. Also, the partial paths are sorted by descending startup
1286  * costs. There may be some paths that require to do startup work by a
1287  * single worker. In such case, it's better for workers to choose the
1288  * expensive ones first, whereas the leader should choose the cheapest
1289  * startup plan.
1290  */
1291  if (pathnode->path.parallel_aware)
1292  {
1293  /*
1294  * We mustn't fiddle with the order of subpaths when the Append has
1295  * pathkeys. The order they're listed in is critical to keeping the
1296  * pathkeys valid.
1297  */
1298  Assert(pathkeys == NIL);
1299 
1301  list_sort(partial_subpaths, append_startup_cost_compare);
1302  }
1303  pathnode->first_partial_path = list_length(subpaths);
1304  pathnode->subpaths = list_concat(subpaths, partial_subpaths);
1305 
1306  /*
1307  * Apply query-wide LIMIT if known and path is for sole base relation.
1308  * (Handling this at this low level is a bit klugy.)
1309  */
1310  if (root != NULL && bms_equal(rel->relids, root->all_baserels))
1311  pathnode->limit_tuples = root->limit_tuples;
1312  else
1313  pathnode->limit_tuples = -1.0;
1314 
1315  foreach(l, pathnode->subpaths)
1316  {
1317  Path *subpath = (Path *) lfirst(l);
1318 
1319  pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1320  subpath->parallel_safe;
1321 
1322  /* All child paths must have same parameterization */
1323  Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
1324  }
1325 
1326  Assert(!parallel_aware || pathnode->path.parallel_safe);
1327 
1328  /*
1329  * If there's exactly one child path, the Append is a no-op and will be
1330  * discarded later (in setrefs.c); therefore, we can inherit the child's
1331  * size and cost, as well as its pathkeys if any (overriding whatever the
1332  * caller might've said). Otherwise, we must do the normal costsize
1333  * calculation.
1334  */
1335  if (list_length(pathnode->subpaths) == 1)
1336  {
1337  Path *child = (Path *) linitial(pathnode->subpaths);
1338 
1339  pathnode->path.rows = child->rows;
1340  pathnode->path.startup_cost = child->startup_cost;
1341  pathnode->path.total_cost = child->total_cost;
1342  pathnode->path.pathkeys = child->pathkeys;
1343  }
1344  else
1345  cost_append(pathnode, root);
1346 
1347  /* If the caller provided a row estimate, override the computed value. */
1348  if (rows >= 0)
1349  pathnode->path.rows = rows;
1350 
1351  return pathnode;
1352 }
void cost_append(AppendPath *apath, PlannerInfo *root)
Definition: costsize.c:2502
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1612
List * list_concat(List *list1, const List *list2)
Definition: list.c:540
@ T_Append
Definition: nodes.h:50
static int append_startup_cost_compare(const ListCell *a, const ListCell *b)
Definition: pathnode.c:1386
static int append_total_cost_compare(const ListCell *a, const ListCell *b)
Definition: pathnode.c:1364
#define IS_PARTITIONED_REL(rel)
Definition: pathnodes.h:787
#define linitial(l)
Definition: pg_list.h:174
ParamPathInfo * get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
Definition: relnode.c:1297
ParamPathInfo * get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
Definition: relnode.c:1594
int first_partial_path
Definition: pathnodes.h:1466
Cardinality limit_tuples
Definition: pathnodes.h:1467
List * subpaths
Definition: pathnodes.h:1464
Cardinality limit_tuples
Definition: pathnodes.h:342
Relids all_baserels
Definition: pathnodes.h:210

References PlannerInfo::all_baserels, append_startup_cost_compare(), append_total_cost_compare(), Assert(), bms_equal(), RelOptInfo::consider_parallel, cost_append(), AppendPath::first_partial_path, get_appendrel_parampathinfo(), get_baserel_parampathinfo(), IS_PARTITIONED_REL, lfirst, PlannerInfo::limit_tuples, AppendPath::limit_tuples, linitial, list_concat(), list_length(), list_sort(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, AppendPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::relids, RELOPT_BASEREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, Path::rows, Path::startup_cost, subpath(), AppendPath::subpaths, T_Append, and Path::total_cost.

Referenced by add_paths_to_append_rel(), create_degenerate_grouping_paths(), generate_nonunion_paths(), generate_orderedappend_paths(), generate_union_paths(), mark_dummy_rel(), reparameterize_path(), and set_dummy_rel_pathlist().

◆ create_bitmap_and_path()

BitmapAndPath* create_bitmap_and_path ( PlannerInfo root,
RelOptInfo rel,
List bitmapquals 
)

Definition at line 1079 of file pathnode.c.

1082 {
1083  BitmapAndPath *pathnode = makeNode(BitmapAndPath);
1084  Relids required_outer = NULL;
1085  ListCell *lc;
1086 
1087  pathnode->path.pathtype = T_BitmapAnd;
1088  pathnode->path.parent = rel;
1089  pathnode->path.pathtarget = rel->reltarget;
1090 
1091  /*
1092  * Identify the required outer rels as the union of what the child paths
1093  * depend on. (Alternatively, we could insist that the caller pass this
1094  * in, but it's more convenient and reliable to compute it here.)
1095  */
1096  foreach(lc, bitmapquals)
1097  {
1098  Path *bitmapqual = (Path *) lfirst(lc);
1099 
1100  required_outer = bms_add_members(required_outer,
1101  PATH_REQ_OUTER(bitmapqual));
1102  }
1103  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1104  required_outer);
1105 
1106  /*
1107  * Currently, a BitmapHeapPath, BitmapAndPath, or BitmapOrPath will be
1108  * parallel-safe if and only if rel->consider_parallel is set. So, we can
1109  * set the flag for this path based only on the relation-level flag,
1110  * without actually iterating over the list of children.
1111  */
1112  pathnode->path.parallel_aware = false;
1113  pathnode->path.parallel_safe = rel->consider_parallel;
1114  pathnode->path.parallel_workers = 0;
1115 
1116  pathnode->path.pathkeys = NIL; /* always unordered */
1117 
1118  pathnode->bitmapquals = bitmapquals;
1119 
1120  /* this sets bitmapselectivity as well as the regular cost fields: */
1121  cost_bitmap_and_node(pathnode, root);
1122 
1123  return pathnode;
1124 }
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:795
void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
Definition: costsize.c:1127
@ T_BitmapAnd
Definition: nodes.h:53
List * bitmapquals
Definition: pathnodes.h:1342

References BitmapAndPath::bitmapquals, bms_add_members(), RelOptInfo::consider_parallel, cost_bitmap_and_node(), get_baserel_parampathinfo(), lfirst, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, BitmapAndPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_BitmapAnd.

Referenced by bitmap_and_cost_est(), and choose_bitmap_and().

◆ create_bitmap_heap_path()

BitmapHeapPath* create_bitmap_heap_path ( PlannerInfo root,
RelOptInfo rel,
Path bitmapqual,
Relids  required_outer,
double  loop_count,
int  parallel_degree 
)

Definition at line 1046 of file pathnode.c.

1052 {
1053  BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);
1054 
1055  pathnode->path.pathtype = T_BitmapHeapScan;
1056  pathnode->path.parent = rel;
1057  pathnode->path.pathtarget = rel->reltarget;
1058  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1059  required_outer);
1060  pathnode->path.parallel_aware = (parallel_degree > 0);
1061  pathnode->path.parallel_safe = rel->consider_parallel;
1062  pathnode->path.parallel_workers = parallel_degree;
1063  pathnode->path.pathkeys = NIL; /* always unordered */
1064 
1065  pathnode->bitmapqual = bitmapqual;
1066 
1067  cost_bitmap_heap_scan(&pathnode->path, root, rel,
1068  pathnode->path.param_info,
1069  bitmapqual, loop_count);
1070 
1071  return pathnode;
1072 }
void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, Path *bitmapqual, double loop_count)
Definition: costsize.c:983
@ T_BitmapHeapScan
Definition: nodes.h:61
Path * bitmapqual
Definition: pathnodes.h:1330

References BitmapHeapPath::bitmapqual, RelOptInfo::consider_parallel, cost_bitmap_heap_scan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, BitmapHeapPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_BitmapHeapScan.

Referenced by create_index_paths(), create_partial_bitmap_paths(), and reparameterize_path().

◆ create_bitmap_or_path()

BitmapOrPath* create_bitmap_or_path ( PlannerInfo root,
RelOptInfo rel,
List bitmapquals 
)

Definition at line 1131 of file pathnode.c.

1134 {
1135  BitmapOrPath *pathnode = makeNode(BitmapOrPath);
1136  Relids required_outer = NULL;
1137  ListCell *lc;
1138 
1139  pathnode->path.pathtype = T_BitmapOr;
1140  pathnode->path.parent = rel;
1141  pathnode->path.pathtarget = rel->reltarget;
1142 
1143  /*
1144  * Identify the required outer rels as the union of what the child paths
1145  * depend on. (Alternatively, we could insist that the caller pass this
1146  * in, but it's more convenient and reliable to compute it here.)
1147  */
1148  foreach(lc, bitmapquals)
1149  {
1150  Path *bitmapqual = (Path *) lfirst(lc);
1151 
1152  required_outer = bms_add_members(required_outer,
1153  PATH_REQ_OUTER(bitmapqual));
1154  }
1155  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1156  required_outer);
1157 
1158  /*
1159  * Currently, a BitmapHeapPath, BitmapAndPath, or BitmapOrPath will be
1160  * parallel-safe if and only if rel->consider_parallel is set. So, we can
1161  * set the flag for this path based only on the relation-level flag,
1162  * without actually iterating over the list of children.
1163  */
1164  pathnode->path.parallel_aware = false;
1165  pathnode->path.parallel_safe = rel->consider_parallel;
1166  pathnode->path.parallel_workers = 0;
1167 
1168  pathnode->path.pathkeys = NIL; /* always unordered */
1169 
1170  pathnode->bitmapquals = bitmapquals;
1171 
1172  /* this sets bitmapselectivity as well as the regular cost fields: */
1173  cost_bitmap_or_node(pathnode, root);
1174 
1175  return pathnode;
1176 }
void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
Definition: costsize.c:1171
@ T_BitmapOr
Definition: nodes.h:54
List * bitmapquals
Definition: pathnodes.h:1355

References BitmapOrPath::bitmapquals, bms_add_members(), RelOptInfo::consider_parallel, cost_bitmap_or_node(), get_baserel_parampathinfo(), lfirst, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, BitmapOrPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_BitmapOr.

Referenced by generate_bitmap_or_paths().

◆ create_ctescan_path()

Path* create_ctescan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 2097 of file pathnode.c.

2098 {
2099  Path *pathnode = makeNode(Path);
2100 
2101  pathnode->pathtype = T_CteScan;
2102  pathnode->parent = rel;
2103  pathnode->pathtarget = rel->reltarget;
2104  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2105  required_outer);
2106  pathnode->parallel_aware = false;
2107  pathnode->parallel_safe = rel->consider_parallel;
2108  pathnode->parallel_workers = 0;
2109  pathnode->pathkeys = NIL; /* XXX for now, result is always unordered */
2110 
2111  cost_ctescan(pathnode, root, rel, pathnode->param_info);
2112 
2113  return pathnode;
2114 }
void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1650
@ T_CteScan
Definition: nodes.h:68

References RelOptInfo::consider_parallel, cost_ctescan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_CteScan.

Referenced by set_cte_pathlist().

◆ create_foreign_join_path()

ForeignPath* create_foreign_join_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
double  rows,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer,
Path fdw_outerpath,
List fdw_private 
)

Definition at line 2251 of file pathnode.c.

2258 {
2259  ForeignPath *pathnode = makeNode(ForeignPath);
2260 
2261  /*
2262  * We should use get_joinrel_parampathinfo to handle parameterized paths,
2263  * but the API of this function doesn't support it, and existing
2264  * extensions aren't yet trying to build such paths anyway. For the
2265  * moment just throw an error if someone tries it; eventually we should
2266  * revisit this.
2267  */
2268  if (!bms_is_empty(required_outer) || !bms_is_empty(rel->lateral_relids))
2269  elog(ERROR, "parameterized foreign joins are not supported yet");
2270 
2271  pathnode->path.pathtype = T_ForeignScan;
2272  pathnode->path.parent = rel;
2273  pathnode->path.pathtarget = target ? target : rel->reltarget;
2274  pathnode->path.param_info = NULL; /* XXX see above */
2275  pathnode->path.parallel_aware = false;
2276  pathnode->path.parallel_safe = rel->consider_parallel;
2277  pathnode->path.parallel_workers = 0;
2278  pathnode->path.rows = rows;
2279  pathnode->path.startup_cost = startup_cost;
2280  pathnode->path.total_cost = total_cost;
2281  pathnode->path.pathkeys = pathkeys;
2282 
2283  pathnode->fdw_outerpath = fdw_outerpath;
2284  pathnode->fdw_private = fdw_private;
2285 
2286  return pathnode;
2287 }
@ T_ForeignScan
Definition: nodes.h:71
Path * fdw_outerpath
Definition: pathnodes.h:1411
List * fdw_private
Definition: pathnodes.h:1412

References bms_is_empty(), RelOptInfo::consider_parallel, elog, ERROR, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, ForeignPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, T_ForeignScan, and Path::total_cost.

Referenced by add_paths_with_pathkeys_for_rel(), and postgresGetForeignJoinPaths().

◆ create_foreign_upper_path()

ForeignPath* create_foreign_upper_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
double  rows,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Path fdw_outerpath,
List fdw_private 
)

Definition at line 2301 of file pathnode.c.

2307 {
2308  ForeignPath *pathnode = makeNode(ForeignPath);
2309 
2310  /*
2311  * Upper relations should never have any lateral references, since joining
2312  * is complete.
2313  */
2315 
2316  pathnode->path.pathtype = T_ForeignScan;
2317  pathnode->path.parent = rel;
2318  pathnode->path.pathtarget = target ? target : rel->reltarget;
2319  pathnode->path.param_info = NULL;
2320  pathnode->path.parallel_aware = false;
2321  pathnode->path.parallel_safe = rel->consider_parallel;
2322  pathnode->path.parallel_workers = 0;
2323  pathnode->path.rows = rows;
2324  pathnode->path.startup_cost = startup_cost;
2325  pathnode->path.total_cost = total_cost;
2326  pathnode->path.pathkeys = pathkeys;
2327 
2328  pathnode->fdw_outerpath = fdw_outerpath;
2329  pathnode->fdw_private = fdw_private;
2330 
2331  return pathnode;
2332 }

References Assert(), bms_is_empty(), RelOptInfo::consider_parallel, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, ForeignPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, T_ForeignScan, and Path::total_cost.

Referenced by add_foreign_final_paths(), add_foreign_grouping_paths(), and add_foreign_ordered_paths().

◆ create_foreignscan_path()

ForeignPath* create_foreignscan_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
double  rows,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer,
Path fdw_outerpath,
List fdw_private 
)

Definition at line 2207 of file pathnode.c.

2214 {
2215  ForeignPath *pathnode = makeNode(ForeignPath);
2216 
2217  /* Historically some FDWs were confused about when to use this */
2218  Assert(IS_SIMPLE_REL(rel));
2219 
2220  pathnode->path.pathtype = T_ForeignScan;
2221  pathnode->path.parent = rel;
2222  pathnode->path.pathtarget = target ? target : rel->reltarget;
2223  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
2224  required_outer);
2225  pathnode->path.parallel_aware = false;
2226  pathnode->path.parallel_safe = rel->consider_parallel;
2227  pathnode->path.parallel_workers = 0;
2228  pathnode->path.rows = rows;
2229  pathnode->path.startup_cost = startup_cost;
2230  pathnode->path.total_cost = total_cost;
2231  pathnode->path.pathkeys = pathkeys;
2232 
2233  pathnode->fdw_outerpath = fdw_outerpath;
2234  pathnode->fdw_private = fdw_private;
2235 
2236  return pathnode;
2237 }
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:655

References Assert(), RelOptInfo::consider_parallel, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, get_baserel_parampathinfo(), IS_SIMPLE_REL, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, ForeignPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, T_ForeignScan, and Path::total_cost.

Referenced by add_paths_with_pathkeys_for_rel(), fileGetForeignPaths(), and postgresGetForeignPaths().

◆ create_functionscan_path()

Path* create_functionscan_path ( PlannerInfo root,
RelOptInfo rel,
List pathkeys,
Relids  required_outer 
)

Definition at line 2019 of file pathnode.c.

2021 {
2022  Path *pathnode = makeNode(Path);
2023 
2024  pathnode->pathtype = T_FunctionScan;
2025  pathnode->parent = rel;
2026  pathnode->pathtarget = rel->reltarget;
2027  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2028  required_outer);
2029  pathnode->parallel_aware = false;
2030  pathnode->parallel_safe = rel->consider_parallel;
2031  pathnode->parallel_workers = 0;
2032  pathnode->pathkeys = pathkeys;
2033 
2034  cost_functionscan(pathnode, root, rel, pathnode->param_info);
2035 
2036  return pathnode;
2037 }
void cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1483
@ T_FunctionScan
Definition: nodes.h:65

References RelOptInfo::consider_parallel, cost_functionscan(), get_baserel_parampathinfo(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_FunctionScan.

Referenced by set_function_pathlist().

◆ create_gather_merge_path()

GatherMergePath* create_gather_merge_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target,
List pathkeys,
Relids  required_outer,
double *  rows 
)

Definition at line 1861 of file pathnode.c.

1864 {
1866  Cost input_startup_cost = 0;
1867  Cost input_total_cost = 0;
1868 
1869  Assert(subpath->parallel_safe);
1870  Assert(pathkeys);
1871 
1872  pathnode->path.pathtype = T_GatherMerge;
1873  pathnode->path.parent = rel;
1874  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1875  required_outer);
1876  pathnode->path.parallel_aware = false;
1877 
1878  pathnode->subpath = subpath;
1879  pathnode->num_workers = subpath->parallel_workers;
1880  pathnode->path.pathkeys = pathkeys;
1881  pathnode->path.pathtarget = target ? target : rel->reltarget;
1882  pathnode->path.rows += subpath->rows;
1883 
1884  if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
1885  {
1886  /* Subpath is adequately ordered, we won't need to sort it */
1887  input_startup_cost += subpath->startup_cost;
1888  input_total_cost += subpath->total_cost;
1889  }
1890  else
1891  {
1892  /* We'll need to insert a Sort node, so include cost for that */
1893  Path sort_path; /* dummy for result of cost_sort */
1894 
1895  cost_sort(&sort_path,
1896  root,
1897  pathkeys,
1898  subpath->total_cost,
1899  subpath->rows,
1900  subpath->pathtarget->width,
1901  0.0,
1902  work_mem,
1903  -1);
1904  input_startup_cost += sort_path.startup_cost;
1905  input_total_cost += sort_path.total_cost;
1906  }
1907 
1908  cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
1909  input_startup_cost, input_total_cost, rows);
1910 
1911  return pathnode;
1912 }
void cost_gather_merge(GatherMergePath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, Cost input_startup_cost, Cost input_total_cost, double *rows)
Definition: costsize.c:444
void cost_sort(Path *path, PlannerInfo *root, List *pathkeys, Cost input_cost, double tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition: costsize.c:2395
int work_mem
Definition: globals.c:125
@ T_GatherMerge
Definition: nodes.h:86
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition: pathkeys.c:329

References Assert(), cost_gather_merge(), cost_sort(), get_baserel_parampathinfo(), makeNode, GatherMergePath::num_workers, Path::parallel_aware, Path::param_info, Path::parent, GatherMergePath::path, Path::pathkeys, pathkeys_contained_in(), Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, subpath(), GatherMergePath::subpath, T_GatherMerge, Path::total_cost, and work_mem.

Referenced by create_ordered_paths(), gather_grouping_paths(), generate_gather_paths(), and generate_useful_gather_paths().

◆ create_gather_path()

GatherPath* create_gather_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target,
Relids  required_outer,
double *  rows 
)

Definition at line 1952 of file pathnode.c.

1954 {
1955  GatherPath *pathnode = makeNode(GatherPath);
1956 
1957  Assert(subpath->parallel_safe);
1958 
1959  pathnode->path.pathtype = T_Gather;
1960  pathnode->path.parent = rel;
1961  pathnode->path.pathtarget = target;
1962  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1963  required_outer);
1964  pathnode->path.parallel_aware = false;
1965  pathnode->path.parallel_safe = false;
1966  pathnode->path.parallel_workers = 0;
1967  pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1968 
1969  pathnode->subpath = subpath;
1970  pathnode->num_workers = subpath->parallel_workers;
1971  pathnode->single_copy = false;
1972 
1973  if (pathnode->num_workers == 0)
1974  {
1975  pathnode->path.pathkeys = subpath->pathkeys;
1976  pathnode->num_workers = 1;
1977  pathnode->single_copy = true;
1978  }
1979 
1980  cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1981 
1982  return pathnode;
1983 }
void cost_gather(GatherPath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, double *rows)
Definition: costsize.c:406
@ T_Gather
Definition: nodes.h:85
bool single_copy
Definition: pathnodes.h:1575
int num_workers
Definition: pathnodes.h:1576

References Assert(), cost_gather(), get_baserel_parampathinfo(), makeNode, NIL, GatherPath::num_workers, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, GatherPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, GatherPath::single_copy, subpath(), GatherPath::subpath, and T_Gather.

Referenced by generate_gather_paths(), and generate_union_paths().

◆ create_group_path()

GroupPath* create_group_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List groupClause,
List qual,
double  numGroups 
)

Definition at line 2986 of file pathnode.c.

2992 {
2993  GroupPath *pathnode = makeNode(GroupPath);
2994  PathTarget *target = rel->reltarget;
2995 
2996  pathnode->path.pathtype = T_Group;
2997  pathnode->path.parent = rel;
2998  pathnode->path.pathtarget = target;
2999  /* For now, assume we are above any joins, so no parameterization */
3000  pathnode->path.param_info = NULL;
3001  pathnode->path.parallel_aware = false;
3002  pathnode->path.parallel_safe = rel->consider_parallel &&
3003  subpath->parallel_safe;
3004  pathnode->path.parallel_workers = subpath->parallel_workers;
3005  /* Group doesn't change sort ordering */
3006  pathnode->path.pathkeys = subpath->pathkeys;
3007 
3008  pathnode->subpath = subpath;
3009 
3010  pathnode->groupClause = groupClause;
3011  pathnode->qual = qual;
3012 
3013  cost_group(&pathnode->path, root,
3014  list_length(groupClause),
3015  numGroups,
3016  qual,
3017  subpath->startup_cost, subpath->total_cost,
3018  subpath->rows);
3019 
3020  /* add tlist eval cost for each output row */
3021  pathnode->path.startup_cost += target->cost.startup;
3022  pathnode->path.total_cost += target->cost.startup +
3023  target->cost.per_tuple * pathnode->path.rows;
3024 
3025  return pathnode;
3026 }
void cost_group(Path *path, PlannerInfo *root, int numGroupCols, double numGroups, List *quals, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition: costsize.c:3191
@ T_Group
Definition: nodes.h:81
List * qual
Definition: pathnodes.h:1758
List * groupClause
Definition: pathnodes.h:1757
Path * subpath
Definition: pathnodes.h:1756
Path path
Definition: pathnodes.h:1755

References RelOptInfo::consider_parallel, PathTarget::cost, cost_group(), GroupPath::groupClause, list_length(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, GroupPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, GroupPath::qual, RelOptInfo::reltarget, Path::rows, QualCost::startup, Path::startup_cost, subpath(), GroupPath::subpath, T_Group, and Path::total_cost.

Referenced by add_paths_to_grouping_rel(), and create_partial_grouping_paths().

◆ create_group_result_path()

GroupResultPath* create_group_result_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
List havingqual 
)

Definition at line 1504 of file pathnode.c.

1506 {
1508 
1509  pathnode->path.pathtype = T_Result;
1510  pathnode->path.parent = rel;
1511  pathnode->path.pathtarget = target;
1512  pathnode->path.param_info = NULL; /* there are no other rels... */
1513  pathnode->path.parallel_aware = false;
1514  pathnode->path.parallel_safe = rel->consider_parallel;
1515  pathnode->path.parallel_workers = 0;
1516  pathnode->path.pathkeys = NIL;
1517  pathnode->quals = havingqual;
1518 
1519  /*
1520  * We can't quite use cost_resultscan() because the quals we want to
1521  * account for are not baserestrict quals of the rel. Might as well just
1522  * hack it here.
1523  */
1524  pathnode->path.rows = 1;
1525  pathnode->path.startup_cost = target->cost.startup;
1526  pathnode->path.total_cost = target->cost.startup +
1527  cpu_tuple_cost + target->cost.per_tuple;
1528 
1529  /*
1530  * Add cost of qual, if any --- but we ignore its selectivity, since our
1531  * rowcount estimate should be 1 no matter what the qual is.
1532  */
1533  if (havingqual)
1534  {
1535  QualCost qual_cost;
1536 
1537  cost_qual_eval(&qual_cost, havingqual, root);
1538  /* havingqual is evaluated once at startup */
1539  pathnode->path.startup_cost += qual_cost.startup + qual_cost.per_tuple;
1540  pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
1541  }
1542 
1543  return pathnode;
1544 }
double cpu_tuple_cost
Definition: costsize.c:122
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition: costsize.c:4667
@ T_Result
Definition: nodes.h:47

References RelOptInfo::consider_parallel, PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, GroupResultPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, GroupResultPath::quals, Path::rows, QualCost::startup, Path::startup_cost, T_Result, and Path::total_cost.

Referenced by create_degenerate_grouping_paths(), and query_planner().

◆ create_groupingsets_path()

GroupingSetsPath* create_groupingsets_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List having_qual,
AggStrategy  aggstrategy,
List rollups,
const AggClauseCosts agg_costs,
double  numGroups 
)

Definition at line 3164 of file pathnode.c.

3172 {
3174  PathTarget *target = rel->reltarget;
3175  ListCell *lc;
3176  bool is_first = true;
3177  bool is_first_sort = true;
3178 
3179  /* The topmost generated Plan node will be an Agg */
3180  pathnode->path.pathtype = T_Agg;
3181  pathnode->path.parent = rel;
3182  pathnode->path.pathtarget = target;
3183  pathnode->path.param_info = subpath->param_info;
3184  pathnode->path.parallel_aware = false;
3185  pathnode->path.parallel_safe = rel->consider_parallel &&
3186  subpath->parallel_safe;
3187  pathnode->path.parallel_workers = subpath->parallel_workers;
3188  pathnode->subpath = subpath;
3189 
3190  /*
3191  * Simplify callers by downgrading AGG_SORTED to AGG_PLAIN, and AGG_MIXED
3192  * to AGG_HASHED, here if possible.
3193  */
3194  if (aggstrategy == AGG_SORTED &&
3195  list_length(rollups) == 1 &&
3196  ((RollupData *) linitial(rollups))->groupClause == NIL)
3197  aggstrategy = AGG_PLAIN;
3198 
3199  if (aggstrategy == AGG_MIXED &&
3200  list_length(rollups) == 1)
3201  aggstrategy = AGG_HASHED;
3202 
3203  /*
3204  * Output will be in sorted order by group_pathkeys if, and only if, there
3205  * is a single rollup operation on a non-empty list of grouping
3206  * expressions.
3207  */
3208  if (aggstrategy == AGG_SORTED && list_length(rollups) == 1)
3209  pathnode->path.pathkeys = root->group_pathkeys;
3210  else
3211  pathnode->path.pathkeys = NIL;
3212 
3213  pathnode->aggstrategy = aggstrategy;
3214  pathnode->rollups = rollups;
3215  pathnode->qual = having_qual;
3216  pathnode->transitionSpace = agg_costs ? agg_costs->transitionSpace : 0;
3217 
3218  Assert(rollups != NIL);
3219  Assert(aggstrategy != AGG_PLAIN || list_length(rollups) == 1);
3220  Assert(aggstrategy != AGG_MIXED || list_length(rollups) > 1);
3221 
3222  foreach(lc, rollups)
3223  {
3224  RollupData *rollup = lfirst(lc);
3225  List *gsets = rollup->gsets;
3226  int numGroupCols = list_length(linitial(gsets));
3227 
3228  /*
3229  * In AGG_SORTED or AGG_PLAIN mode, the first rollup takes the
3230  * (already-sorted) input, and following ones do their own sort.
3231  *
3232  * In AGG_HASHED mode, there is one rollup for each grouping set.
3233  *
3234  * In AGG_MIXED mode, the first rollups are hashed, the first
3235  * non-hashed one takes the (already-sorted) input, and following ones
3236  * do their own sort.
3237  */
3238  if (is_first)
3239  {
3240  cost_agg(&pathnode->path, root,
3241  aggstrategy,
3242  agg_costs,
3243  numGroupCols,
3244  rollup->numGroups,
3245  having_qual,
3246  subpath->startup_cost,
3247  subpath->total_cost,
3248  subpath->rows,
3249  subpath->pathtarget->width);
3250  is_first = false;
3251  if (!rollup->is_hashed)
3252  is_first_sort = false;
3253  }
3254  else
3255  {
3256  Path sort_path; /* dummy for result of cost_sort */
3257  Path agg_path; /* dummy for result of cost_agg */
3258 
3259  if (rollup->is_hashed || is_first_sort)
3260  {
3261  /*
3262  * Account for cost of aggregation, but don't charge input
3263  * cost again
3264  */
3265  cost_agg(&agg_path, root,
3266  rollup->is_hashed ? AGG_HASHED : AGG_SORTED,
3267  agg_costs,
3268  numGroupCols,
3269  rollup->numGroups,
3270  having_qual,
3271  0.0, 0.0,
3272  subpath->rows,
3273  subpath->pathtarget->width);
3274  if (!rollup->is_hashed)
3275  is_first_sort = false;
3276  }
3277  else
3278  {
3279  /* Account for cost of sort, but don't charge input cost again */
3280  cost_sort(&sort_path, root, NIL,
3281  0.0,
3282  subpath->rows,
3283  subpath->pathtarget->width,
3284  0.0,
3285  work_mem,
3286  -1.0);
3287 
3288  /* Account for cost of aggregation */
3289 
3290  cost_agg(&agg_path, root,
3291  AGG_SORTED,
3292  agg_costs,
3293  numGroupCols,
3294  rollup->numGroups,
3295  having_qual,
3296  sort_path.startup_cost,
3297  sort_path.total_cost,
3298  sort_path.rows,
3299  subpath->pathtarget->width);
3300  }
3301 
3302  pathnode->path.total_cost += agg_path.total_cost;
3303  pathnode->path.rows += agg_path.rows;
3304  }
3305  }
3306 
3307  /* add tlist eval cost for each output row */
3308  pathnode->path.startup_cost += target->cost.startup;
3309  pathnode->path.total_cost += target->cost.startup +
3310  target->cost.per_tuple * pathnode->path.rows;
3311 
3312  return pathnode;
3313 }
@ AGG_HASHED
Definition: nodes.h:809
@ AGG_MIXED
Definition: nodes.h:810
@ AGG_PLAIN
Definition: nodes.h:807
uint64 transitionSpace
Definition: pathnodes.h:1826
AggStrategy aggstrategy
Definition: pathnodes.h:1823
List * group_pathkeys
Definition: pathnodes.h:297
Cardinality numGroups
Definition: pathnodes.h:1810
List * gsets
Definition: pathnodes.h:1808
bool is_hashed
Definition: pathnodes.h:1812

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, GroupingSetsPath::aggstrategy, Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), cost_sort(), PlannerInfo::group_pathkeys, RollupData::gsets, RollupData::is_hashed, lfirst, linitial, list_length(), makeNode, NIL, RollupData::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, GroupingSetsPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, GroupingSetsPath::qual, RelOptInfo::reltarget, GroupingSetsPath::rollups, Path::rows, QualCost::startup, Path::startup_cost, subpath(), GroupingSetsPath::subpath, T_Agg, Path::total_cost, AggClauseCosts::transitionSpace, GroupingSetsPath::transitionSpace, and work_mem.

Referenced by consider_groupingsets_paths().

◆ create_hashjoin_path()

HashPath* create_hashjoin_path ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
JoinCostWorkspace workspace,
JoinPathExtraData extra,
Path outer_path,
Path inner_path,
bool  parallel_hash,
List restrict_clauses,
Relids  required_outer,
List hashclauses 
)

Definition at line 2561 of file pathnode.c.

2572 {
2573  HashPath *pathnode = makeNode(HashPath);
2574 
2575  pathnode->jpath.path.pathtype = T_HashJoin;
2576  pathnode->jpath.path.parent = joinrel;
2577  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2578  pathnode->jpath.path.param_info =
2580  joinrel,
2581  outer_path,
2582  inner_path,
2583  extra->sjinfo,
2584  required_outer,
2585  &restrict_clauses);
2586  pathnode->jpath.path.parallel_aware =
2587  joinrel->consider_parallel && parallel_hash;
2588  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2589  outer_path->parallel_safe && inner_path->parallel_safe;
2590  /* This is a foolish way to estimate parallel_workers, but for now... */
2591  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2592 
2593  /*
2594  * A hashjoin never has pathkeys, since its output ordering is
2595  * unpredictable due to possible batching. XXX If the inner relation is
2596  * small enough, we could instruct the executor that it must not batch,
2597  * and then we could assume that the output inherits the outer relation's
2598  * ordering, which might save a sort step. However there is considerable
2599  * downside if our estimate of the inner relation size is badly off. For
2600  * the moment we don't risk it. (Note also that if we wanted to take this
2601  * seriously, joinpath.c would have to consider many more paths for the
2602  * outer rel than it does now.)
2603  */
2604  pathnode->jpath.path.pathkeys = NIL;
2605  pathnode->jpath.jointype = jointype;
2606  pathnode->jpath.inner_unique = extra->inner_unique;
2607  pathnode->jpath.outerjoinpath = outer_path;
2608  pathnode->jpath.innerjoinpath = inner_path;
2609  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2610  pathnode->path_hashclauses = hashclauses;
2611  /* final_cost_hashjoin will fill in pathnode->num_batches */
2612 
2613  final_cost_hashjoin(root, pathnode, workspace, extra);
2614 
2615  return pathnode;
2616 }
void final_cost_hashjoin(PlannerInfo *root, HashPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:4208
@ T_HashJoin
Definition: nodes.h:76
ParamPathInfo * get_joinrel_parampathinfo(PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, Relids required_outer, List **restrict_clauses)
Definition: relnode.c:1387
List * path_hashclauses
Definition: pathnodes.h:1682
JoinPath jpath
Definition: pathnodes.h:1681
SpecialJoinInfo * sjinfo
Definition: pathnodes.h:2552
Path * outerjoinpath
Definition: pathnodes.h:1604
Path path
Definition: pathnodes.h:1597
Path * innerjoinpath
Definition: pathnodes.h:1605
JoinType jointype
Definition: pathnodes.h:1599
bool inner_unique
Definition: pathnodes.h:1601
List * joinrestrictinfo
Definition: pathnodes.h:1607

References RelOptInfo::consider_parallel, final_cost_hashjoin(), get_joinrel_parampathinfo(), JoinPath::inner_unique, JoinPathExtraData::inner_unique, JoinPath::innerjoinpath, JoinPath::joinrestrictinfo, JoinPath::jointype, HashPath::jpath, makeNode, NIL, JoinPath::outerjoinpath, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, JoinPath::path, HashPath::path_hashclauses, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, JoinPathExtraData::sjinfo, and T_HashJoin.

Referenced by try_hashjoin_path(), and try_partial_hashjoin_path().

◆ create_incremental_sort_path()

IncrementalSortPath* create_incremental_sort_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List pathkeys,
int  presorted_keys,
double  limit_tuples 
)

Definition at line 2893 of file pathnode.c.

2899 {
2901  SortPath *pathnode = &sort->spath;
2902 
2903  pathnode->path.pathtype = T_IncrementalSort;
2904  pathnode->path.parent = rel;
2905  /* Sort doesn't project, so use source path's pathtarget */
2906  pathnode->path.pathtarget = subpath->pathtarget;
2907  /* For now, assume we are above any joins, so no parameterization */
2908  pathnode->path.param_info = NULL;
2909  pathnode->path.parallel_aware = false;
2910  pathnode->path.parallel_safe = rel->consider_parallel &&
2911  subpath->parallel_safe;
2912  pathnode->path.parallel_workers = subpath->parallel_workers;
2913  pathnode->path.pathkeys = pathkeys;
2914 
2915  pathnode->subpath = subpath;
2916 
2917  cost_incremental_sort(&pathnode->path,
2918  root, pathkeys, presorted_keys,
2919  subpath->startup_cost,
2920  subpath->total_cost,
2921  subpath->rows,
2922  subpath->pathtarget->width,
2923  0.0, /* XXX comparison_cost shouldn't be 0? */
2924  work_mem, limit_tuples);
2925 
2926  sort->nPresortedCols = presorted_keys;
2927 
2928  return sort;
2929 }
Datum sort(PG_FUNCTION_ARGS)
Definition: _int_op.c:195
void cost_incremental_sort(Path *path, PlannerInfo *root, List *pathkeys, int presorted_keys, Cost input_startup_cost, Cost input_total_cost, double input_tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition: costsize.c:2255
@ T_IncrementalSort
Definition: nodes.h:80
Path path
Definition: pathnodes.h:1729
Path * subpath
Definition: pathnodes.h:1730

References RelOptInfo::consider_parallel, cost_incremental_sort(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, SortPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, sort(), subpath(), SortPath::subpath, T_IncrementalSort, and work_mem.

Referenced by add_paths_to_grouping_rel(), create_one_window_path(), create_ordered_paths(), create_partial_grouping_paths(), gather_grouping_paths(), and generate_useful_gather_paths().

◆ create_index_path()

IndexPath* create_index_path ( PlannerInfo root,
IndexOptInfo index,
List indexclauses,
List indexorderbys,
List indexorderbycols,
List pathkeys,
ScanDirection  indexscandir,
bool  indexonly,
Relids  required_outer,
double  loop_count,
bool  partial_path 
)

Definition at line 997 of file pathnode.c.

1008 {
1009  IndexPath *pathnode = makeNode(IndexPath);
1010  RelOptInfo *rel = index->rel;
1011 
1012  pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
1013  pathnode->path.parent = rel;
1014  pathnode->path.pathtarget = rel->reltarget;
1015  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1016  required_outer);
1017  pathnode->path.parallel_aware = false;
1018  pathnode->path.parallel_safe = rel->consider_parallel;
1019  pathnode->path.parallel_workers = 0;
1020  pathnode->path.pathkeys = pathkeys;
1021 
1022  pathnode->indexinfo = index;
1023  pathnode->indexclauses = indexclauses;
1024  pathnode->indexorderbys = indexorderbys;
1025  pathnode->indexorderbycols = indexorderbycols;
1026  pathnode->indexscandir = indexscandir;
1027 
1028  cost_index(pathnode, root, loop_count, partial_path);
1029 
1030  return pathnode;
1031 }
void cost_index(IndexPath *path, PlannerInfo *root, double loop_count, bool partial_path)
Definition: costsize.c:519
@ T_IndexOnlyScan
Definition: nodes.h:59
@ T_IndexScan
Definition: nodes.h:58
List * indexclauses
Definition: pathnodes.h:1258
ScanDirection indexscandir
Definition: pathnodes.h:1261
Path path
Definition: pathnodes.h:1256
List * indexorderbycols
Definition: pathnodes.h:1260
List * indexorderbys
Definition: pathnodes.h:1259
IndexOptInfo * indexinfo
Definition: pathnodes.h:1257
Definition: type.h:90

References RelOptInfo::consider_parallel, cost_index(), get_baserel_parampathinfo(), IndexPath::indexclauses, IndexPath::indexinfo, IndexPath::indexorderbycols, IndexPath::indexorderbys, IndexPath::indexscandir, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, IndexPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, T_IndexOnlyScan, and T_IndexScan.

Referenced by build_index_paths(), and plan_cluster_use_sort().

◆ create_limit_path()

LimitPath* create_limit_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
Node limitOffset,
Node limitCount,
LimitOption  limitOption,
int64  offset_est,
int64  count_est 
)

Definition at line 3736 of file pathnode.c.

3741 {
3742  LimitPath *pathnode = makeNode(LimitPath);
3743 
3744  pathnode->path.pathtype = T_Limit;
3745  pathnode->path.parent = rel;
3746  /* Limit doesn't project, so use source path's pathtarget */
3747  pathnode->path.pathtarget = subpath->pathtarget;
3748  /* For now, assume we are above any joins, so no parameterization */
3749  pathnode->path.param_info = NULL;
3750  pathnode->path.parallel_aware = false;
3751  pathnode->path.parallel_safe = rel->consider_parallel &&
3752  subpath->parallel_safe;
3753  pathnode->path.parallel_workers = subpath->parallel_workers;
3754  pathnode->path.rows = subpath->rows;
3755  pathnode->path.startup_cost = subpath->startup_cost;
3756  pathnode->path.total_cost = subpath->total_cost;
3757  pathnode->path.pathkeys = subpath->pathkeys;
3758  pathnode->subpath = subpath;
3759  pathnode->limitOffset = limitOffset;
3760  pathnode->limitCount = limitCount;
3761  pathnode->limitOption = limitOption;
3762 
3763  /*
3764  * Adjust the output rows count and costs according to the offset/limit.
3765  */
3766  adjust_limit_rows_costs(&pathnode->path.rows,
3767  &pathnode->path.startup_cost,
3768  &pathnode->path.total_cost,
3769  offset_est, count_est);
3770 
3771  return pathnode;
3772 }
@ T_Limit
Definition: nodes.h:90
void adjust_limit_rows_costs(double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
Definition: pathnode.c:3791
Path path
Definition: pathnodes.h:1923
Path * subpath
Definition: pathnodes.h:1924
LimitOption limitOption
Definition: pathnodes.h:1927
Node * limitOffset
Definition: pathnodes.h:1925
Node * limitCount
Definition: pathnodes.h:1926

References adjust_limit_rows_costs(), RelOptInfo::consider_parallel, LimitPath::limitCount, LimitPath::limitOffset, LimitPath::limitOption, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, LimitPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, Path::rows, Path::startup_cost, subpath(), LimitPath::subpath, T_Limit, and Path::total_cost.

Referenced by grouping_planner().

◆ create_lockrows_path()

LockRowsPath* create_lockrows_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List rowMarks,
int  epqParam 
)

Definition at line 3576 of file pathnode.c.

3578 {
3579  LockRowsPath *pathnode = makeNode(LockRowsPath);
3580 
3581  pathnode->path.pathtype = T_LockRows;
3582  pathnode->path.parent = rel;
3583  /* LockRows doesn't project, so use source path's pathtarget */
3584  pathnode->path.pathtarget = subpath->pathtarget;
3585  /* For now, assume we are above any joins, so no parameterization */
3586  pathnode->path.param_info = NULL;
3587  pathnode->path.parallel_aware = false;
3588  pathnode->path.parallel_safe = false;
3589  pathnode->path.parallel_workers = 0;
3590  pathnode->path.rows = subpath->rows;
3591 
3592  /*
3593  * The result cannot be assumed sorted, since locking might cause the sort
3594  * key columns to be replaced with new values.
3595  */
3596  pathnode->path.pathkeys = NIL;
3597 
3598  pathnode->subpath = subpath;
3599  pathnode->rowMarks = rowMarks;
3600  pathnode->epqParam = epqParam;
3601 
3602  /*
3603  * We should charge something extra for the costs of row locking and
3604  * possible refetches, but it's hard to say how much. For now, use
3605  * cpu_tuple_cost per row.
3606  */
3607  pathnode->path.startup_cost = subpath->startup_cost;
3608  pathnode->path.total_cost = subpath->total_cost +
3609  cpu_tuple_cost * subpath->rows;
3610 
3611  return pathnode;
3612 }
@ T_LockRows
Definition: nodes.h:89
Path * subpath
Definition: pathnodes.h:1886
List * rowMarks
Definition: pathnodes.h:1887

References cpu_tuple_cost, LockRowsPath::epqParam, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, LockRowsPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, LockRowsPath::rowMarks, Path::rows, Path::startup_cost, subpath(), LockRowsPath::subpath, T_LockRows, and Path::total_cost.

Referenced by grouping_planner().

◆ create_material_path()

MaterialPath* create_material_path ( RelOptInfo rel,
Path subpath 
)

Definition at line 1552 of file pathnode.c.

1553 {
1554  MaterialPath *pathnode = makeNode(MaterialPath);
1555 
1556  Assert(subpath->parent == rel);
1557 
1558  pathnode->path.pathtype = T_Material;
1559  pathnode->path.parent = rel;
1560  pathnode->path.pathtarget = rel->reltarget;
1561  pathnode->path.param_info = subpath->param_info;
1562  pathnode->path.parallel_aware = false;
1563  pathnode->path.parallel_safe = rel->consider_parallel &&
1564  subpath->parallel_safe;
1565  pathnode->path.parallel_workers = subpath->parallel_workers;
1566  pathnode->path.pathkeys = subpath->pathkeys;
1567 
1568  pathnode->subpath = subpath;
1569 
1570  cost_material(&pathnode->path,
1571  subpath->startup_cost,
1572  subpath->total_cost,
1573  subpath->rows,
1574  subpath->pathtarget->width);
1575 
1576  return pathnode;
1577 }
void cost_material(Path *path, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition: costsize.c:2724
@ T_Material
Definition: nodes.h:77
Path * subpath
Definition: pathnodes.h:1514

References Assert(), RelOptInfo::consider_parallel, cost_material(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, MaterialPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, subpath(), MaterialPath::subpath, and T_Material.

Referenced by match_unsorted_outer(), and set_tablesample_rel_pathlist().

◆ create_memoize_path()

MemoizePath* create_memoize_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List param_exprs,
List hash_operators,
bool  singlerow,
bool  binary_mode,
double  calls 
)

Definition at line 1584 of file pathnode.c.

1587 {
1588  MemoizePath *pathnode = makeNode(MemoizePath);
1589 
1590  Assert(subpath->parent == rel);
1591 
1592  pathnode->path.pathtype = T_Memoize;
1593  pathnode->path.parent = rel;
1594  pathnode->path.pathtarget = rel->reltarget;
1595  pathnode->path.param_info = subpath->param_info;
1596  pathnode->path.parallel_aware = false;
1597  pathnode->path.parallel_safe = rel->consider_parallel &&
1598  subpath->parallel_safe;
1599  pathnode->path.parallel_workers = subpath->parallel_workers;
1600  pathnode->path.pathkeys = subpath->pathkeys;
1601 
1602  pathnode->subpath = subpath;
1603  pathnode->hash_operators = hash_operators;
1604  pathnode->param_exprs = param_exprs;
1605  pathnode->singlerow = singlerow;
1606  pathnode->binary_mode = binary_mode;
1607  pathnode->calls = calls;
1608 
1609  /*
1610  * For now we set est_entries to 0. cost_memoize_rescan() does all the
1611  * hard work to determine how many cache entries there are likely to be,
1612  * so it seems best to leave it up to that function to fill this field in.
1613  * If left at 0, the executor will make a guess at a good value.
1614  */
1615  pathnode->est_entries = 0;
1616 
1617  /*
1618  * Add a small additional charge for caching the first entry. All the
1619  * harder calculations for rescans are performed in cost_memoize_rescan().
1620  */
1621  pathnode->path.startup_cost = subpath->startup_cost + cpu_tuple_cost;
1622  pathnode->path.total_cost = subpath->total_cost + cpu_tuple_cost;
1623  pathnode->path.rows = subpath->rows;
1624 
1625  return pathnode;
1626 }
@ T_Memoize
Definition: nodes.h:78
bool singlerow
Definition: pathnodes.h:1528
List * hash_operators
Definition: pathnodes.h:1526
uint32 est_entries
Definition: pathnodes.h:1533
bool binary_mode
Definition: pathnodes.h:1530
Cardinality calls
Definition: pathnodes.h:1532
Path * subpath
Definition: pathnodes.h:1525
List * param_exprs
Definition: pathnodes.h:1527

References Assert(), MemoizePath::binary_mode, MemoizePath::calls, RelOptInfo::consider_parallel, cpu_tuple_cost, MemoizePath::est_entries, MemoizePath::hash_operators, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, MemoizePath::param_exprs, Path::param_info, Path::parent, MemoizePath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, Path::rows, MemoizePath::singlerow, Path::startup_cost, subpath(), MemoizePath::subpath, T_Memoize, and Path::total_cost.

Referenced by get_memoize_path(), and reparameterize_path().

◆ create_merge_append_path()

MergeAppendPath* create_merge_append_path ( PlannerInfo root,
RelOptInfo rel,
List subpaths,
List pathkeys,
Relids  required_outer 
)

Definition at line 1404 of file pathnode.c.

1409 {
1411  Cost input_startup_cost;
1412  Cost input_total_cost;
1413  ListCell *l;
1414 
1415  pathnode->path.pathtype = T_MergeAppend;
1416  pathnode->path.parent = rel;
1417  pathnode->path.pathtarget = rel->reltarget;
1419  required_outer);
1420  pathnode->path.parallel_aware = false;
1421  pathnode->path.parallel_safe = rel->consider_parallel;
1422  pathnode->path.parallel_workers = 0;
1423  pathnode->path.pathkeys = pathkeys;
1424  pathnode->subpaths = subpaths;
1425 
1426  /*
1427  * Apply query-wide LIMIT if known and path is for sole base relation.
1428  * (Handling this at this low level is a bit klugy.)
1429  */
1430  if (bms_equal(rel->relids, root->all_baserels))
1431  pathnode->limit_tuples = root->limit_tuples;
1432  else
1433  pathnode->limit_tuples = -1.0;
1434 
1435  /*
1436  * Add up the sizes and costs of the input paths.
1437  */
1438  pathnode->path.rows = 0;
1439  input_startup_cost = 0;
1440  input_total_cost = 0;
1441  foreach(l, subpaths)
1442  {
1443  Path *subpath = (Path *) lfirst(l);
1444 
1445  pathnode->path.rows += subpath->rows;
1446  pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1447  subpath->parallel_safe;
1448 
1449  if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
1450  {
1451  /* Subpath is adequately ordered, we won't need to sort it */
1452  input_startup_cost += subpath->startup_cost;
1453  input_total_cost += subpath->total_cost;
1454  }
1455  else
1456  {
1457  /* We'll need to insert a Sort node, so include cost for that */
1458  Path sort_path; /* dummy for result of cost_sort */
1459 
1460  cost_sort(&sort_path,
1461  root,
1462  pathkeys,
1463  subpath->total_cost,
1464  subpath->parent->tuples,
1465  subpath->pathtarget->width,
1466  0.0,
1467  work_mem,
1468  pathnode->limit_tuples);
1469  input_startup_cost += sort_path.startup_cost;
1470  input_total_cost += sort_path.total_cost;
1471  }
1472 
1473  /* All child paths must have same parameterization */
1474  Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
1475  }
1476 
1477  /*
1478  * Now we can compute total costs of the MergeAppend. If there's exactly
1479  * one child path, the MergeAppend is a no-op and will be discarded later
1480  * (in setrefs.c); otherwise we do the normal cost calculation.
1481  */
1482  if (list_length(subpaths) == 1)
1483  {
1484  pathnode->path.startup_cost = input_startup_cost;
1485  pathnode->path.total_cost = input_total_cost;
1486  }
1487  else
1488  cost_merge_append(&pathnode->path, root,
1489  pathkeys, list_length(subpaths),
1490  input_startup_cost, input_total_cost,
1491  pathnode->path.rows);
1492 
1493  return pathnode;
1494 }
void cost_merge_append(Path *path, PlannerInfo *root, List *pathkeys, int n_streams, Cost input_startup_cost, Cost input_total_cost, double tuples)
Definition: costsize.c:2675
@ T_MergeAppend
Definition: nodes.h:51
Cardinality limit_tuples
Definition: pathnodes.h:1489

References PlannerInfo::all_baserels, Assert(), bms_equal(), RelOptInfo::consider_parallel, cost_merge_append(), cost_sort(), get_appendrel_parampathinfo(), lfirst, PlannerInfo::limit_tuples, MergeAppendPath::limit_tuples, list_length(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, MergeAppendPath::path, PATH_REQ_OUTER, Path::pathkeys, pathkeys_contained_in(), Path::pathtarget, Path::pathtype, RelOptInfo::relids, RelOptInfo::reltarget, Path::rows, Path::startup_cost, subpath(), MergeAppendPath::subpaths, T_MergeAppend, Path::total_cost, and work_mem.

Referenced by generate_orderedappend_paths().

◆ create_mergejoin_path()

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 at line 2495 of file pathnode.c.

2508 {
2509  MergePath *pathnode = makeNode(MergePath);
2510 
2511  pathnode->jpath.path.pathtype = T_MergeJoin;
2512  pathnode->jpath.path.parent = joinrel;
2513  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2514  pathnode->jpath.path.param_info =
2516  joinrel,
2517  outer_path,
2518  inner_path,
2519  extra->sjinfo,
2520  required_outer,
2521  &restrict_clauses);
2522  pathnode->jpath.path.parallel_aware = false;
2523  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2524  outer_path->parallel_safe && inner_path->parallel_safe;
2525  /* This is a foolish way to estimate parallel_workers, but for now... */
2526  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2527  pathnode->jpath.path.pathkeys = pathkeys;
2528  pathnode->jpath.jointype = jointype;
2529  pathnode->jpath.inner_unique = extra->inner_unique;
2530  pathnode->jpath.outerjoinpath = outer_path;
2531  pathnode->jpath.innerjoinpath = inner_path;
2532  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2533  pathnode->path_mergeclauses = mergeclauses;
2534  pathnode->outersortkeys = outersortkeys;
2535  pathnode->innersortkeys = innersortkeys;
2536  /* pathnode->skip_mark_restore will be set by final_cost_mergejoin */
2537  /* pathnode->materialize_inner will be set by final_cost_mergejoin */
2538 
2539  final_cost_mergejoin(root, pathnode, workspace, extra);
2540 
2541  return pathnode;
2542 }
void final_cost_mergejoin(PlannerInfo *root, MergePath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:3772
@ T_MergeJoin
Definition: nodes.h:75
List * outersortkeys
Definition: pathnodes.h:1664
List * innersortkeys
Definition: pathnodes.h:1665
JoinPath jpath
Definition: pathnodes.h:1662
List * path_mergeclauses
Definition: pathnodes.h:1663

References RelOptInfo::consider_parallel, final_cost_mergejoin(), get_joinrel_parampathinfo(), JoinPath::inner_unique, JoinPathExtraData::inner_unique, JoinPath::innerjoinpath, MergePath::innersortkeys, JoinPath::joinrestrictinfo, JoinPath::jointype, MergePath::jpath, makeNode, JoinPath::outerjoinpath, MergePath::outersortkeys, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, JoinPath::path, MergePath::path_mergeclauses, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, JoinPathExtraData::sjinfo, and T_MergeJoin.

Referenced by try_mergejoin_path(), and try_partial_mergejoin_path().

◆ create_minmaxagg_path()

MinMaxAggPath* create_minmaxagg_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
List mmaggregates,
List quals 
)

Definition at line 3325 of file pathnode.c.

3330 {
3331  MinMaxAggPath *pathnode = makeNode(MinMaxAggPath);
3332  Cost initplan_cost;
3333  ListCell *lc;
3334 
3335  /* The topmost generated Plan node will be a Result */
3336  pathnode->path.pathtype = T_Result;
3337  pathnode->path.parent = rel;
3338  pathnode->path.pathtarget = target;
3339  /* For now, assume we are above any joins, so no parameterization */
3340  pathnode->path.param_info = NULL;
3341  pathnode->path.parallel_aware = false;
3342  /* A MinMaxAggPath implies use of subplans, so cannot be parallel-safe */
3343  pathnode->path.parallel_safe = false;
3344  pathnode->path.parallel_workers = 0;
3345  /* Result is one unordered row */
3346  pathnode->path.rows = 1;
3347  pathnode->path.pathkeys = NIL;
3348 
3349  pathnode->mmaggregates = mmaggregates;
3350  pathnode->quals = quals;
3351 
3352  /* Calculate cost of all the initplans ... */
3353  initplan_cost = 0;
3354  foreach(lc, mmaggregates)
3355  {
3356  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3357 
3358  initplan_cost += mminfo->pathcost;
3359  }
3360 
3361  /* add tlist eval cost for each output row, plus cpu_tuple_cost */
3362  pathnode->path.startup_cost = initplan_cost + target->cost.startup;
3363  pathnode->path.total_cost = initplan_cost + target->cost.startup +
3364  target->cost.per_tuple + cpu_tuple_cost;
3365 
3366  /*
3367  * Add cost of qual, if any --- but we ignore its selectivity, since our
3368  * rowcount estimate should be 1 no matter what the qual is.
3369  */
3370  if (quals)
3371  {
3372  QualCost qual_cost;
3373 
3374  cost_qual_eval(&qual_cost, quals, root);
3375  pathnode->path.startup_cost += qual_cost.startup;
3376  pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
3377  }
3378 
3379  return pathnode;
3380 }
List * quals
Definition: pathnodes.h:1836
List * mmaggregates
Definition: pathnodes.h:1835

References PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, lfirst, makeNode, MinMaxAggPath::mmaggregates, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, MinMaxAggPath::path, MinMaxAggInfo::pathcost, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, MinMaxAggPath::quals, Path::rows, QualCost::startup, Path::startup_cost, T_Result, and Path::total_cost.

Referenced by preprocess_minmax_aggregates().

◆ create_modifytable_path()

ModifyTablePath* create_modifytable_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
CmdType  operation,
bool  canSetTag,
Index  nominalRelation,
Index  rootRelation,
bool  partColsUpdated,
List resultRelations,
List updateColnosLists,
List withCheckOptionLists,
List returningLists,
List rowMarks,
OnConflictExpr onconflict,
List mergeActionLists,
int  epqParam 
)

Definition at line 3637 of file pathnode.c.

3647 {
3649 
3650  Assert(operation == CMD_MERGE ||
3651  (operation == CMD_UPDATE ?
3652  list_length(resultRelations) == list_length(updateColnosLists) :
3653  updateColnosLists == NIL));
3654  Assert(withCheckOptionLists == NIL ||
3655  list_length(resultRelations) == list_length(withCheckOptionLists));
3656  Assert(returningLists == NIL ||
3657  list_length(resultRelations) == list_length(returningLists));
3658 
3659  pathnode->path.pathtype = T_ModifyTable;
3660  pathnode->path.parent = rel;
3661  /* pathtarget is not interesting, just make it minimally valid */
3662  pathnode->path.pathtarget = rel->reltarget;
3663  /* For now, assume we are above any joins, so no parameterization */
3664  pathnode->path.param_info = NULL;
3665  pathnode->path.parallel_aware = false;
3666  pathnode->path.parallel_safe = false;
3667  pathnode->path.parallel_workers = 0;
3668  pathnode->path.pathkeys = NIL;
3669 
3670  /*
3671  * Compute cost & rowcount as subpath cost & rowcount (if RETURNING)
3672  *
3673  * Currently, we don't charge anything extra for the actual table
3674  * modification work, nor for the WITH CHECK OPTIONS or RETURNING
3675  * expressions if any. It would only be window dressing, since
3676  * ModifyTable is always a top-level node and there is no way for the
3677  * costs to change any higher-level planning choices. But we might want
3678  * to make it look better sometime.
3679  */
3680  pathnode->path.startup_cost = subpath->startup_cost;
3681  pathnode->path.total_cost = subpath->total_cost;
3682  if (returningLists != NIL)
3683  {
3684  pathnode->path.rows = subpath->rows;
3685 
3686  /*
3687  * Set width to match the subpath output. XXX this is totally wrong:
3688  * we should return an average of the RETURNING tlist widths. But
3689  * it's what happened historically, and improving it is a task for
3690  * another day. (Again, it's mostly window dressing.)
3691  */
3692  pathnode->path.pathtarget->width = subpath->pathtarget->width;
3693  }
3694  else
3695  {
3696  pathnode->path.rows = 0;
3697  pathnode->path.pathtarget->width = 0;
3698  }
3699 
3700  pathnode->subpath = subpath;
3701  pathnode->operation = operation;
3702  pathnode->canSetTag = canSetTag;
3703  pathnode->nominalRelation = nominalRelation;
3704  pathnode->rootRelation = rootRelation;
3705  pathnode->partColsUpdated = partColsUpdated;
3706  pathnode->resultRelations = resultRelations;
3707  pathnode->updateColnosLists = updateColnosLists;
3708  pathnode->withCheckOptionLists = withCheckOptionLists;
3709  pathnode->returningLists = returningLists;
3710  pathnode->rowMarks = rowMarks;
3711  pathnode->onconflict = onconflict;
3712  pathnode->epqParam = epqParam;
3713  pathnode->mergeActionLists = mergeActionLists;
3714 
3715  return pathnode;
3716 }
@ CMD_MERGE
Definition: nodes.h:725
@ CMD_UPDATE
Definition: nodes.h:722
@ T_ModifyTable
Definition: nodes.h:49
bool partColsUpdated
Definition: pathnodes.h:1906
List * returningLists
Definition: pathnodes.h:1910
List * resultRelations
Definition: pathnodes.h:1907
List * withCheckOptionLists
Definition: pathnodes.h:1909
List * updateColnosLists
Definition: pathnodes.h:1908
OnConflictExpr * onconflict
Definition: pathnodes.h:1912
CmdType operation
Definition: pathnodes.h:1902
Index rootRelation
Definition: pathnodes.h:1905
Index nominalRelation
Definition: pathnodes.h:1904
List * mergeActionLists
Definition: pathnodes.h:1914

References Assert(), ModifyTablePath::canSetTag, CMD_MERGE, CMD_UPDATE, ModifyTablePath::epqParam, list_length(), makeNode, ModifyTablePath::mergeActionLists, NIL, ModifyTablePath::nominalRelation, ModifyTablePath::onconflict, ModifyTablePath::operation, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, ModifyTablePath::partColsUpdated, ModifyTablePath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, ModifyTablePath::resultRelations, ModifyTablePath::returningLists, ModifyTablePath::rootRelation, ModifyTablePath::rowMarks, Path::rows, Path::startup_cost, subpath(), ModifyTablePath::subpath, T_ModifyTable, Path::total_cost, ModifyTablePath::updateColnosLists, PathTarget::width, and ModifyTablePath::withCheckOptionLists.

Referenced by grouping_planner().

◆ create_namedtuplestorescan_path()

Path* create_namedtuplestorescan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 2122 of file pathnode.c.

2124 {
2125  Path *pathnode = makeNode(Path);
2126 
2127  pathnode->pathtype = T_NamedTuplestoreScan;
2128  pathnode->parent = rel;
2129  pathnode->pathtarget = rel->reltarget;
2130  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2131  required_outer);
2132  pathnode->parallel_aware = false;
2133  pathnode->parallel_safe = rel->consider_parallel;
2134  pathnode->parallel_workers = 0;
2135  pathnode->pathkeys = NIL; /* result is always unordered */
2136 
2137  cost_namedtuplestorescan(pathnode, root, rel, pathnode->param_info);
2138 
2139  return pathnode;
2140 }
void cost_namedtuplestorescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1691
@ T_NamedTuplestoreScan
Definition: nodes.h:69

References RelOptInfo::consider_parallel, cost_namedtuplestorescan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_NamedTuplestoreScan.

Referenced by set_namedtuplestore_pathlist().

◆ create_nestloop_path()

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 at line 2407 of file pathnode.c.

2417 {
2418  NestPath *pathnode = makeNode(NestPath);
2419  Relids inner_req_outer = PATH_REQ_OUTER(inner_path);
2420 
2421  /*
2422  * If the inner path is parameterized by the outer, we must drop any
2423  * restrict_clauses that are due to be moved into the inner path. We have
2424  * to do this now, rather than postpone the work till createplan time,
2425  * because the restrict_clauses list can affect the size and cost
2426  * estimates for this path.
2427  */
2428  if (bms_overlap(inner_req_outer, outer_path->parent->relids))
2429  {
2430  Relids inner_and_outer = bms_union(inner_path->parent->relids,
2431  inner_req_outer);
2432  List *jclauses = NIL;
2433  ListCell *lc;
2434 
2435  foreach(lc, restrict_clauses)
2436  {
2437  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2438 
2439  if (!join_clause_is_movable_into(rinfo,
2440  inner_path->parent->relids,
2441  inner_and_outer))
2442  jclauses = lappend(jclauses, rinfo);
2443  }
2444  restrict_clauses = jclauses;
2445  }
2446 
2447  pathnode->jpath.path.pathtype = T_NestLoop;
2448  pathnode->jpath.path.parent = joinrel;
2449  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2450  pathnode->jpath.path.param_info =
2452  joinrel,
2453  outer_path,
2454  inner_path,
2455  extra->sjinfo,
2456  required_outer,
2457  &restrict_clauses);
2458  pathnode->jpath.path.parallel_aware = false;
2459  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2460  outer_path->parallel_safe && inner_path->parallel_safe;
2461  /* This is a foolish way to estimate parallel_workers, but for now... */
2462  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2463  pathnode->jpath.path.pathkeys = pathkeys;
2464  pathnode->jpath.jointype = jointype;
2465  pathnode->jpath.inner_unique = extra->inner_unique;
2466  pathnode->jpath.outerjoinpath = outer_path;
2467  pathnode->jpath.innerjoinpath = inner_path;
2468  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2469 
2470  final_cost_nestloop(root, pathnode, workspace, extra);
2471 
2472  return pathnode;
2473 }
void final_cost_nestloop(PlannerInfo *root, NestPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:3336
@ T_NestLoop
Definition: nodes.h:74
bool join_clause_is_movable_into(RestrictInfo *rinfo, Relids currentrelids, Relids current_and_outer)
Definition: restrictinfo.c:600
JoinPath jpath
Definition: pathnodes.h:1622

References bms_overlap(), bms_union(), RelOptInfo::consider_parallel, final_cost_nestloop(), get_joinrel_parampathinfo(), JoinPath::inner_unique, JoinPathExtraData::inner_unique, JoinPath::innerjoinpath, join_clause_is_movable_into(), JoinPath::joinrestrictinfo, JoinPath::jointype, NestPath::jpath, lappend(), lfirst, makeNode, NIL, JoinPath::outerjoinpath, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, JoinPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::relids, RelOptInfo::reltarget, JoinPathExtraData::sjinfo, and T_NestLoop.

Referenced by try_nestloop_path(), and try_partial_nestloop_path().

◆ create_projection_path()

ProjectionPath* create_projection_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target 
)

Definition at line 2627 of file pathnode.c.

2631 {
2632  ProjectionPath *pathnode = makeNode(ProjectionPath);
2633  PathTarget *oldtarget;
2634 
2635  /*
2636  * We mustn't put a ProjectionPath directly above another; it's useless
2637  * and will confuse create_projection_plan. Rather than making sure all
2638  * callers handle that, let's implement it here, by stripping off any
2639  * ProjectionPath in what we're given. Given this rule, there won't be
2640  * more than one.
2641  */
2642  if (IsA(subpath, ProjectionPath))
2643  {
2644  ProjectionPath *subpp = (ProjectionPath *) subpath;
2645 
2646  Assert(subpp->path.parent == rel);
2647  subpath = subpp->subpath;
2649  }
2650 
2651  pathnode->path.pathtype = T_Result;
2652  pathnode->path.parent = rel;
2653  pathnode->path.pathtarget = target;
2654  /* For now, assume we are above any joins, so no parameterization */
2655  pathnode->path.param_info = NULL;
2656  pathnode->path.parallel_aware = false;
2657  pathnode->path.parallel_safe = rel->consider_parallel &&
2658  subpath->parallel_safe &&
2659  is_parallel_safe(root, (Node *) target->exprs);
2660  pathnode->path.parallel_workers = subpath->parallel_workers;
2661  /* Projection does not change the sort order */
2662  pathnode->path.pathkeys = subpath->pathkeys;
2663 
2664  pathnode->subpath = subpath;
2665 
2666  /*
2667  * We might not need a separate Result node. If the input plan node type
2668  * can project, we can just tell it to project something else. Or, if it
2669  * can't project but the desired target has the same expression list as
2670  * what the input will produce anyway, we can still give it the desired
2671  * tlist (possibly changing its ressortgroupref labels, but nothing else).
2672  * Note: in the latter case, create_projection_plan has to recheck our
2673  * conclusion; see comments therein.
2674  */
2675  oldtarget = subpath->pathtarget;
2677  equal(oldtarget->exprs, target->exprs))
2678  {
2679  /* No separate Result node needed */
2680  pathnode->dummypp = true;
2681 
2682  /*
2683  * Set cost of plan as subpath's cost, adjusted for tlist replacement.
2684  */
2685  pathnode->path.rows = subpath->rows;
2686  pathnode->path.startup_cost = subpath->startup_cost +
2687  (target->cost.startup - oldtarget->cost.startup);
2688  pathnode->path.total_cost = subpath->total_cost +
2689  (target->cost.startup - oldtarget->cost.startup) +
2690  (target->cost.per_tuple - oldtarget->cost.per_tuple) * subpath->rows;
2691  }
2692  else
2693  {
2694  /* We really do need the Result node */
2695  pathnode->dummypp = false;
2696 
2697  /*
2698  * The Result node's cost is cpu_tuple_cost per row, plus the cost of
2699  * evaluating the tlist. There is no qual to worry about.
2700  */
2701  pathnode->path.rows = subpath->rows;
2702  pathnode->path.startup_cost = subpath->startup_cost +
2703  target->cost.startup;
2704  pathnode->path.total_cost = subpath->total_cost +
2705  target->cost.startup +
2706  (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows;
2707  }
2708 
2709  return pathnode;
2710 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3564
Path * subpath
Definition: pathnodes.h:1704

References Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cpu_tuple_cost, ProjectionPath::dummypp, equal(), PathTarget::exprs, is_parallel_safe(), is_projection_capable_path(), IsA, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, ProjectionPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, Path::rows, QualCost::startup, Path::startup_cost, subpath(), ProjectionPath::subpath, T_Result, and Path::total_cost.

Referenced by adjust_paths_for_srfs(), apply_projection_to_path(), apply_scanjoin_target_to_paths(), and recurse_set_operations().

◆ create_recursiveunion_path()

RecursiveUnionPath* create_recursiveunion_path ( PlannerInfo root,
RelOptInfo rel,
Path leftpath,
Path rightpath,
PathTarget target,
List distinctList,
int  wtParam,
double  numGroups 
)

Definition at line 3531 of file pathnode.c.

3539 {
3541 
3542  pathnode->path.pathtype = T_RecursiveUnion;
3543  pathnode->path.parent = rel;
3544  pathnode->path.pathtarget = target;
3545  /* For now, assume we are above any joins, so no parameterization */
3546  pathnode->path.param_info = NULL;
3547  pathnode->path.parallel_aware = false;
3548  pathnode->path.parallel_safe = rel->consider_parallel &&
3549  leftpath->parallel_safe && rightpath->parallel_safe;
3550  /* Foolish, but we'll do it like joins for now: */
3551  pathnode->path.parallel_workers = leftpath->parallel_workers;
3552  /* RecursiveUnion result is always unsorted */
3553  pathnode->path.pathkeys = NIL;
3554 
3555  pathnode->leftpath = leftpath;
3556  pathnode->rightpath = rightpath;
3557  pathnode->distinctList = distinctList;
3558  pathnode->wtParam = wtParam;
3559  pathnode->numGroups = numGroups;
3560 
3561  cost_recursive_union(&pathnode->path, leftpath, rightpath);
3562 
3563  return pathnode;
3564 }
void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
Definition: costsize.c:1765
@ T_RecursiveUnion
Definition: nodes.h:52
Cardinality numGroups
Definition: pathnodes.h:1877

References RelOptInfo::consider_parallel, cost_recursive_union(), RecursiveUnionPath::distinctList, RecursiveUnionPath::leftpath, makeNode, NIL, RecursiveUnionPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, RecursiveUnionPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RecursiveUnionPath::rightpath, T_RecursiveUnion, and RecursiveUnionPath::wtParam.

Referenced by generate_recursion_path().

◆ create_resultscan_path()

Path* create_resultscan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 2148 of file pathnode.c.

2150 {
2151  Path *pathnode = makeNode(Path);
2152 
2153  pathnode->pathtype = T_Result;
2154  pathnode->parent = rel;
2155  pathnode->pathtarget = rel->reltarget;
2156  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2157  required_outer);
2158  pathnode->parallel_aware = false;
2159  pathnode->parallel_safe = rel->consider_parallel;
2160  pathnode->parallel_workers = 0;
2161  pathnode->pathkeys = NIL; /* result is always unordered */
2162 
2163  cost_resultscan(pathnode, root, rel, pathnode->param_info);
2164 
2165  return pathnode;
2166 }
void cost_resultscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1728

References RelOptInfo::consider_parallel, cost_resultscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_Result.

Referenced by reparameterize_path(), and set_result_pathlist().

◆ create_samplescan_path()

Path* create_samplescan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 954 of file pathnode.c.

955 {
956  Path *pathnode = makeNode(Path);
957 
958  pathnode->pathtype = T_SampleScan;
959  pathnode->parent = rel;
960  pathnode->pathtarget = rel->reltarget;
961  pathnode->param_info = get_baserel_parampathinfo(root, rel,
962  required_outer);
963  pathnode->parallel_aware = false;
964  pathnode->parallel_safe = rel->consider_parallel;
965  pathnode->parallel_workers = 0;
966  pathnode->pathkeys = NIL; /* samplescan has unordered result */
967 
968  cost_samplescan(pathnode, root, rel, pathnode->param_info);
969 
970  return pathnode;
971 }
void cost_samplescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:331
@ T_SampleScan
Definition: nodes.h:57

References RelOptInfo::consider_parallel, cost_samplescan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_SampleScan.

Referenced by reparameterize_path(), and set_tablesample_rel_pathlist().

◆ create_seqscan_path()

Path* create_seqscan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer,
int  parallel_workers 
)

Definition at line 929 of file pathnode.c.

931 {
932  Path *pathnode = makeNode(Path);
933 
934  pathnode->pathtype = T_SeqScan;
935  pathnode->parent = rel;
936  pathnode->pathtarget = rel->reltarget;
937  pathnode->param_info = get_baserel_parampathinfo(root, rel,
938  required_outer);
939  pathnode->parallel_aware = (parallel_workers > 0);
940  pathnode->parallel_safe = rel->consider_parallel;
941  pathnode->parallel_workers = parallel_workers;
942  pathnode->pathkeys = NIL; /* seqscan has unordered result */
943 
944  cost_seqscan(pathnode, root, rel, pathnode->param_info);
945 
946  return pathnode;
947 }
void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:254
@ T_SeqScan
Definition: nodes.h:56

References RelOptInfo::consider_parallel, cost_seqscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_SeqScan.

Referenced by create_plain_partial_paths(), plan_cluster_use_sort(), reparameterize_path(), and set_plain_rel_pathlist().

◆ create_set_projection_path()

ProjectSetPath* create_set_projection_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target 
)

Definition at line 2824 of file pathnode.c.

2828 {
2829  ProjectSetPath *pathnode = makeNode(ProjectSetPath);
2830  double tlist_rows;
2831  ListCell *lc;
2832 
2833  pathnode->path.pathtype = T_ProjectSet;
2834  pathnode->path.parent = rel;
2835  pathnode->path.pathtarget = target;
2836  /* For now, assume we are above any joins, so no parameterization */
2837  pathnode->path.param_info = NULL;
2838  pathnode->path.parallel_aware = false;
2839  pathnode->path.parallel_safe = rel->consider_parallel &&
2840  subpath->parallel_safe &&
2841  is_parallel_safe(root, (Node *) target->exprs);
2842  pathnode->path.parallel_workers = subpath->parallel_workers;
2843  /* Projection does not change the sort order XXX? */
2844  pathnode->path.pathkeys = subpath->pathkeys;
2845 
2846  pathnode->subpath = subpath;
2847 
2848  /*
2849  * Estimate number of rows produced by SRFs for each row of input; if
2850  * there's more than one in this node, use the maximum.
2851  */
2852  tlist_rows = 1;
2853  foreach(lc, target->exprs)
2854  {
2855  Node *node = (Node *) lfirst(lc);
2856  double itemrows;
2857 
2858  itemrows = expression_returns_set_rows(root, node);
2859  if (tlist_rows < itemrows)
2860  tlist_rows = itemrows;
2861  }
2862 
2863  /*
2864  * In addition to the cost of evaluating the tlist, charge cpu_tuple_cost
2865  * per input row, and half of cpu_tuple_cost for each added output row.
2866  * This is slightly bizarre maybe, but it's what 9.6 did; we may revisit
2867  * this estimate later.
2868  */
2869  pathnode->path.rows = subpath->rows * tlist_rows;
2870  pathnode->path.startup_cost = subpath->startup_cost +
2871  target->cost.startup;
2872  pathnode->path.total_cost = subpath->total_cost +
2873  target->cost.startup +
2874  (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows +
2875  (pathnode->path.rows - subpath->rows) * cpu_tuple_cost / 2;
2876 
2877  return pathnode;
2878 }
double expression_returns_set_rows(PlannerInfo *root, Node *clause)
Definition: clauses.c:292
@ T_ProjectSet
Definition: nodes.h:48
Path * subpath
Definition: pathnodes.h:1716

References RelOptInfo::consider_parallel, PathTarget::cost, cpu_tuple_cost, expression_returns_set_rows(), PathTarget::exprs, is_parallel_safe(), lfirst, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, ProjectSetPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, Path::rows, QualCost::startup, Path::startup_cost, subpath(), ProjectSetPath::subpath, T_ProjectSet, and Path::total_cost.

Referenced by adjust_paths_for_srfs().

◆ create_setop_path()

SetOpPath* create_setop_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
SetOpCmd  cmd,
SetOpStrategy  strategy,
List distinctList,
AttrNumber  flagColIdx,
int  firstFlag,
double  numGroups,
double  outputRows 
)

Definition at line 3469 of file pathnode.c.

3479 {
3480  SetOpPath *pathnode = makeNode(SetOpPath);
3481 
3482  pathnode->path.pathtype = T_SetOp;
3483  pathnode->path.parent = rel;
3484  /* SetOp doesn't project, so use source path's pathtarget */
3485  pathnode->path.pathtarget = subpath->pathtarget;
3486  /* For now, assume we are above any joins, so no parameterization */
3487  pathnode->path.param_info = NULL;
3488  pathnode->path.parallel_aware = false;
3489  pathnode->path.parallel_safe = rel->consider_parallel &&
3490  subpath->parallel_safe;
3491  pathnode->path.parallel_workers = subpath->parallel_workers;
3492  /* SetOp preserves the input sort order if in sort mode */
3493  pathnode->path.pathkeys =
3494  (strategy == SETOP_SORTED) ? subpath->pathkeys : NIL;
3495 
3496  pathnode->subpath = subpath;
3497  pathnode->cmd = cmd;
3498  pathnode->strategy = strategy;
3499  pathnode->distinctList = distinctList;
3500  pathnode->flagColIdx = flagColIdx;
3501  pathnode->firstFlag = firstFlag;
3502  pathnode->numGroups = numGroups;
3503 
3504  /*
3505  * Charge one cpu_operator_cost per comparison per input tuple. We assume
3506  * all columns get compared at most of the tuples.
3507  */
3508  pathnode->path.startup_cost = subpath->startup_cost;
3509  pathnode->path.total_cost = subpath->total_cost +
3510  cpu_operator_cost * subpath->rows * list_length(distinctList);
3511  pathnode->path.rows = outputRows;
3512 
3513  return pathnode;
3514 }
double cpu_operator_cost
Definition: costsize.c:124
@ SETOP_SORTED
Definition: nodes.h:859
@ T_SetOp
Definition: nodes.h:88
List * distinctList
Definition: pathnodes.h:1861
Cardinality numGroups
Definition: pathnodes.h:1864
int firstFlag
Definition: pathnodes.h:1863
Path * subpath
Definition: pathnodes.h:1858
SetOpCmd cmd
Definition: pathnodes.h:1859
Path path
Definition: pathnodes.h:1857
SetOpStrategy strategy
Definition: pathnodes.h:1860
AttrNumber flagColIdx
Definition: pathnodes.h:1862

References SetOpPath::cmd, RelOptInfo::consider_parallel, cpu_operator_cost, SetOpPath::distinctList, SetOpPath::firstFlag, SetOpPath::flagColIdx, list_length(), makeNode, NIL, SetOpPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, SetOpPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, Path::rows, SETOP_SORTED, Path::startup_cost, SetOpPath::strategy, subpath(), SetOpPath::subpath, T_SetOp, and Path::total_cost.

Referenced by generate_nonunion_paths().

◆ create_sort_path()

SortPath* create_sort_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List pathkeys,
double  limit_tuples 
)

Definition at line 2942 of file pathnode.c.

2947 {
2948  SortPath *pathnode = makeNode(SortPath);
2949 
2950  pathnode->path.pathtype = T_Sort;
2951  pathnode->path.parent = rel;
2952  /* Sort doesn't project, so use source path's pathtarget */
2953  pathnode->path.pathtarget = subpath->pathtarget;
2954  /* For now, assume we are above any joins, so no parameterization */
2955  pathnode->path.param_info = NULL;
2956  pathnode->path.parallel_aware = false;
2957  pathnode->path.parallel_safe = rel->consider_parallel &&
2958  subpath->parallel_safe;
2959  pathnode->path.parallel_workers = subpath->parallel_workers;
2960  pathnode->path.pathkeys = pathkeys;
2961 
2962  pathnode->subpath = subpath;
2963 
2964  cost_sort(&pathnode->path, root, pathkeys,
2965  subpath->total_cost,
2966  subpath->rows,
2967  subpath->pathtarget->width,
2968  0.0, /* XXX comparison_cost shouldn't be 0? */
2969  work_mem, limit_tuples);
2970 
2971  return pathnode;
2972 }
@ T_Sort
Definition: nodes.h:79

References RelOptInfo::consider_parallel, cost_sort(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, SortPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, subpath(), SortPath::subpath, T_Sort, and work_mem.

Referenced by add_paths_to_grouping_rel(), add_paths_with_pathkeys_for_rel(), create_final_distinct_paths(), create_one_window_path(), create_ordered_paths(), create_partial_grouping_paths(), gather_grouping_paths(), generate_nonunion_paths(), generate_useful_gather_paths(), and make_union_unique().

◆ create_subqueryscan_path()

SubqueryScanPath* create_subqueryscan_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List pathkeys,
Relids  required_outer 
)

Definition at line 1991 of file pathnode.c.

1993 {
1995 
1996  pathnode->path.pathtype = T_SubqueryScan;
1997  pathnode->path.parent = rel;
1998  pathnode->path.pathtarget = rel->reltarget;
1999  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
2000  required_outer);
2001  pathnode->path.parallel_aware = false;
2002  pathnode->path.parallel_safe = rel->consider_parallel &&
2003  subpath->parallel_safe;
2004  pathnode->path.parallel_workers = subpath->parallel_workers;
2005  pathnode->path.pathkeys = pathkeys;
2006  pathnode->subpath = subpath;
2007 
2008  cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info);
2009 
2010  return pathnode;
2011 }
void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1420
@ T_SubqueryScan
Definition: nodes.h:64

References RelOptInfo::consider_parallel, cost_subqueryscan(), get_baserel_parampathinfo(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, SubqueryScanPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, subpath(), SubqueryScanPath::subpath, and T_SubqueryScan.

Referenced by recurse_set_operations(), reparameterize_path(), and set_subquery_pathlist().

◆ create_tablefuncscan_path()

Path* create_tablefuncscan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)

Definition at line 2045 of file pathnode.c.

2047 {
2048  Path *pathnode = makeNode(Path);
2049 
2050  pathnode->pathtype = T_TableFuncScan;
2051  pathnode->parent = rel;
2052  pathnode->pathtarget = rel->reltarget;
2053  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2054  required_outer);
2055  pathnode->parallel_aware = false;
2056  pathnode->parallel_safe = rel->consider_parallel;
2057  pathnode->parallel_workers = 0;
2058  pathnode->pathkeys = NIL; /* result is always unordered */
2059 
2060  cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
2061 
2062  return pathnode;
2063 }
void cost_tablefuncscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1544
@ T_TableFuncScan
Definition: nodes.h:67

References RelOptInfo::consider_parallel, cost_tablefuncscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, and T_TableFuncScan.

Referenced by set_tablefunc_pathlist().

◆ create_tidrangescan_path()

TidRangePath* create_tidrangescan_path ( PlannerInfo root,
RelOptInfo rel,
List tidrangequals,
Relids  required_outer 
)

Definition at line 1212 of file pathnode.c.

1214 {
1215  TidRangePath *pathnode = makeNode(TidRangePath);
1216 
1217  pathnode->path.pathtype = T_TidRangeScan;
1218  pathnode->path.parent = rel;
1219  pathnode->path.pathtarget = rel->reltarget;
1220  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1221  required_outer);
1222  pathnode->path.parallel_aware = false;
1223  pathnode->path.parallel_safe = rel->consider_parallel;
1224  pathnode->path.parallel_workers = 0;
1225  pathnode->path.pathkeys = NIL; /* always unordered */
1226 
1227  pathnode->tidrangequals = tidrangequals;
1228 
1229  cost_tidrangescan(&pathnode->path, root, rel, tidrangequals,
1230  pathnode->path.param_info);
1231 
1232  return pathnode;
1233 }
void cost_tidrangescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, List *tidrangequals, ParamPathInfo *param_info)
Definition: costsize.c:1327
@ T_TidRangeScan
Definition: nodes.h:63
List * tidrangequals
Definition: pathnodes.h:1381

References RelOptInfo::consider_parallel, cost_tidrangescan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, TidRangePath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, T_TidRangeScan, and TidRangePath::tidrangequals.

Referenced by create_tidscan_paths().

◆ create_tidscan_path()

TidPath* create_tidscan_path ( PlannerInfo root,
RelOptInfo rel,
List tidquals,
Relids  required_outer 
)

Definition at line 1183 of file pathnode.c.

1185 {
1186  TidPath *pathnode = makeNode(TidPath);
1187 
1188  pathnode->path.pathtype = T_TidScan;
1189  pathnode->path.parent = rel;
1190  pathnode->path.pathtarget = rel->reltarget;
1191  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1192  required_outer);
1193  pathnode->path.parallel_aware = false;
1194  pathnode->path.parallel_safe = rel->consider_parallel;
1195  pathnode->path.parallel_workers = 0;
1196  pathnode->path.pathkeys = NIL; /* always unordered */
1197 
1198  pathnode->tidquals = tidquals;
1199 
1200  cost_tidscan(&pathnode->path, root, rel, tidquals,
1201  pathnode->path.param_info);
1202 
1203  return pathnode;
1204 }
void cost_tidscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info)
Definition: costsize.c:1219
@ T_TidScan
Definition: nodes.h:62
List * tidquals
Definition: pathnodes.h:1369
Path path
Definition: pathnodes.h:1368

References RelOptInfo::consider_parallel, cost_tidscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, TidPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, RelOptInfo::reltarget, T_TidScan, and TidPath::tidquals.

Referenced by BuildParameterizedTidPaths(), and create_tidscan_paths().

◆ create_unique_path()

UniquePath* create_unique_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
SpecialJoinInfo sjinfo 
)

Definition at line 1640 of file pathnode.c.

1642 {
1643  UniquePath *pathnode;
1644  Path sort_path; /* dummy for result of cost_sort */
1645  Path agg_path; /* dummy for result of cost_agg */
1646  MemoryContext oldcontext;
1647  int numCols;
1648 
1649  /* Caller made a mistake if subpath isn't cheapest_total ... */
1651  Assert(subpath->parent == rel);
1652  /* ... or if SpecialJoinInfo is the wrong one */
1653  Assert(sjinfo->jointype == JOIN_SEMI);
1654  Assert(bms_equal(rel->relids, sjinfo->syn_righthand));
1655 
1656  /* If result already cached, return it */
1657  if (rel->cheapest_unique_path)
1658  return (UniquePath *) rel->cheapest_unique_path;
1659 
1660  /* If it's not possible to unique-ify, return NULL */
1661  if (!(sjinfo->semi_can_btree || sjinfo->semi_can_hash))
1662  return NULL;
1663 
1664  /*
1665  * When called during GEQO join planning, we are in a short-lived memory
1666  * context. We must make sure that the path and any subsidiary data
1667  * structures created for a baserel survive the GEQO cycle, else the
1668  * baserel is trashed for future GEQO cycles. On the other hand, when we
1669  * are creating those for a joinrel during GEQO, we don't want them to
1670  * clutter the main planning context. Upshot is that the best solution is
1671  * to explicitly allocate memory in the same context the given RelOptInfo
1672  * is in.
1673  */
1674  oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel));
1675 
1676  pathnode = makeNode(UniquePath);
1677 
1678  pathnode->path.pathtype = T_Unique;
1679  pathnode->path.parent = rel;
1680  pathnode->path.pathtarget = rel->reltarget;
1681  pathnode->path.param_info = subpath->param_info;
1682  pathnode->path.parallel_aware = false;
1683  pathnode->path.parallel_safe = rel->consider_parallel &&
1684  subpath->parallel_safe;
1685  pathnode->path.parallel_workers = subpath->parallel_workers;
1686 
1687  /*
1688  * Assume the output is unsorted, since we don't necessarily have pathkeys
1689  * to represent it. (This might get overridden below.)
1690  */
1691  pathnode->path.pathkeys = NIL;
1692 
1693  pathnode->subpath = subpath;
1694  pathnode->in_operators = sjinfo->semi_operators;
1695  pathnode->uniq_exprs = sjinfo->semi_rhs_exprs;
1696 
1697  /*
1698  * If the input is a relation and it has a unique index that proves the
1699  * semi_rhs_exprs are unique, then we don't need to do anything. Note
1700  * that relation_has_unique_index_for automatically considers restriction
1701  * clauses for the rel, as well.
1702  */
1703  if (rel->rtekind == RTE_RELATION && sjinfo->semi_can_btree &&
1705  sjinfo->semi_rhs_exprs,
1706  sjinfo->semi_operators))
1707  {
1708  pathnode->umethod = UNIQUE_PATH_NOOP;
1709  pathnode->path.rows = rel->rows;
1710  pathnode->path.startup_cost = subpath->startup_cost;
1711  pathnode->path.total_cost = subpath->total_cost;
1712  pathnode->path.pathkeys = subpath->pathkeys;
1713 
1714  rel->cheapest_unique_path = (Path *) pathnode;
1715 
1716  MemoryContextSwitchTo(oldcontext);
1717 
1718  return pathnode;
1719  }
1720 
1721  /*
1722  * If the input is a subquery whose output must be unique already, then we
1723  * don't need to do anything. The test for uniqueness has to consider
1724  * exactly which columns we are extracting; for example "SELECT DISTINCT
1725  * x,y" doesn't guarantee that x alone is distinct. So we cannot check for
1726  * this optimization unless semi_rhs_exprs consists only of simple Vars
1727  * referencing subquery outputs. (Possibly we could do something with
1728  * expressions in the subquery outputs, too, but for now keep it simple.)
1729  */
1730  if (rel->rtekind == RTE_SUBQUERY)
1731  {
1732  RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
1733 
1735  {
1736  List *sub_tlist_colnos;
1737 
1738  sub_tlist_colnos = translate_sub_tlist(sjinfo->semi_rhs_exprs,
1739  rel->relid);
1740 
1741  if (sub_tlist_colnos &&
1743  sub_tlist_colnos,
1744  sjinfo->semi_operators))
1745  {
1746  pathnode->umethod = UNIQUE_PATH_NOOP;
1747  pathnode->path.rows = rel->rows;
1748  pathnode->path.startup_cost = subpath->startup_cost;
1749  pathnode->path.total_cost = subpath->total_cost;
1750  pathnode->path.pathkeys = subpath->pathkeys;
1751 
1752  rel->cheapest_unique_path = (Path *) pathnode;
1753 
1754  MemoryContextSwitchTo(oldcontext);
1755 
1756  return pathnode;
1757  }
1758  }
1759  }
1760 
1761  /* Estimate number of output rows */
1762  pathnode->path.rows = estimate_num_groups(root,
1763  sjinfo->semi_rhs_exprs,
1764  rel->rows,
1765  NULL,
1766  NULL);
1767  numCols = list_length(sjinfo->semi_rhs_exprs);
1768 
1769  if (sjinfo->semi_can_btree)
1770  {
1771  /*
1772  * Estimate cost for sort+unique implementation
1773  */
1774  cost_sort(&sort_path, root, NIL,
1775  subpath->total_cost,
1776  rel->rows,
1777  subpath->pathtarget->width,
1778  0.0,
1779  work_mem,
1780  -1.0);
1781 
1782  /*
1783  * Charge one cpu_operator_cost per comparison per input tuple. We
1784  * assume all columns get compared at most of the tuples. (XXX
1785  * probably this is an overestimate.) This should agree with
1786  * create_upper_unique_path.
1787  */
1788  sort_path.total_cost += cpu_operator_cost * rel->rows * numCols;
1789  }
1790 
1791  if (sjinfo->semi_can_hash)
1792  {
1793  /*
1794  * Estimate the overhead per hashtable entry at 64 bytes (same as in
1795  * planner.c).
1796  */
1797  int hashentrysize = subpath->pathtarget->width + 64;
1798 
1799  if (hashentrysize * pathnode->path.rows > get_hash_memory_limit())
1800  {
1801  /*
1802  * We should not try to hash. Hack the SpecialJoinInfo to
1803  * remember this, in case we come through here again.
1804  */
1805  sjinfo->semi_can_hash = false;
1806  }
1807  else
1808  cost_agg(&agg_path, root,
1809  AGG_HASHED, NULL,
1810  numCols, pathnode->path.rows,
1811  NIL,
1812  subpath->startup_cost,
1813  subpath->total_cost,
1814  rel->rows,
1815  subpath->pathtarget->width);
1816  }
1817 
1818  if (sjinfo->semi_can_btree && sjinfo->semi_can_hash)
1819  {
1820  if (agg_path.total_cost < sort_path.total_cost)
1821  pathnode->umethod = UNIQUE_PATH_HASH;
1822  else
1823  pathnode->umethod = UNIQUE_PATH_SORT;
1824  }
1825  else if (sjinfo->semi_can_btree)
1826  pathnode->umethod = UNIQUE_PATH_SORT;
1827  else if (sjinfo->semi_can_hash)
1828  pathnode->umethod = UNIQUE_PATH_HASH;
1829  else
1830  {
1831  /* we can get here only if we abandoned hashing above */
1832  MemoryContextSwitchTo(oldcontext);
1833  return NULL;
1834  }
1835 
1836  if (pathnode->umethod == UNIQUE_PATH_HASH)
1837  {
1838  pathnode->path.startup_cost = agg_path.startup_cost;
1839  pathnode->path.total_cost = agg_path.total_cost;
1840  }
1841  else
1842  {
1843  pathnode->path.startup_cost = sort_path.startup_cost;
1844  pathnode->path.total_cost = sort_path.total_cost;
1845  }
1846 
1847  rel->cheapest_unique_path = (Path *) pathnode;
1848 
1849  MemoryContextSwitchTo(oldcontext);
1850 
1851  return pathnode;
1852 }
bool query_is_distinct_for(Query *query, List *colnos, List *opids)
Definition: analyzejoins.c:775
bool query_supports_distinctness(Query *query)
Definition: analyzejoins.c:738
bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, List *restrictlist, List *exprlist, List *oprlist)
Definition: indxpath.c:3498
static MemoryContext GetMemoryChunkContext(void *pointer)
Definition: memutils.h:114
size_t get_hash_memory_limit(void)
Definition: nodeHash.c:3401
@ T_Unique
Definition: nodes.h:84
@ JOIN_SEMI
Definition: nodes.h:763
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static List * translate_sub_tlist(List *tlist, int relid)
Definition: pathnode.c:1926
@ UNIQUE_PATH_SORT
Definition: pathnodes.h:1554
@ UNIQUE_PATH_NOOP
Definition: pathnodes.h:1552
@ UNIQUE_PATH_HASH
Definition: pathnodes.h:1553