PostgreSQL Source Code  git master
pathnode.c File Reference
#include "postgres.h"
#include <math.h>
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/extensible.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/appendinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/selfuncs.h"
Include dependency graph for pathnode.c:

Go to the source code of this file.

Macros

#define STD_FUZZ_FACTOR   1.01
 
#define CONSIDER_PATH_STARTUP_COST(p)    ((p)->param_info == NULL ? (p)->parent->consider_startup : (p)->parent->consider_param_startup)
 
#define FLAT_COPY_PATH(newnode, node, nodetype)
 
#define ADJUST_CHILD_ATTRS(node)
 
#define REPARAMETERIZE_CHILD_PATH(path)
 
#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist)
 

Enumerations

enum  PathCostComparison { COSTS_EQUAL , COSTS_BETTER1 , COSTS_BETTER2 , COSTS_DIFFERENT }
 

Functions

static Listtranslate_sub_tlist (List *tlist, int relid)
 
static int append_total_cost_compare (const ListCell *a, const ListCell *b)
 
static int append_startup_cost_compare (const ListCell *a, const ListCell *b)
 
static Listreparameterize_pathlist_by_child (PlannerInfo *root, List *pathlist, RelOptInfo *child_rel)
 
int compare_path_costs (Path *path1, Path *path2, CostSelector criterion)
 
int compare_fractional_path_costs (Path *path1, Path *path2, double fraction)
 
static PathCostComparison compare_path_costs_fuzzily (Path *path1, Path *path2, double fuzz_factor)
 
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)
 
GatherMergePathcreate_gather_merge_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *pathkeys, Relids required_outer, double *rows)
 
GatherPathcreate_gather_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, 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_tablefuncscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_valuesscan_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)
 
IncrementalSortPathcreate_incremental_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
 
SortPathcreate_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, 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)
 

Macro Definition Documentation

◆ ADJUST_CHILD_ATTRS

#define ADJUST_CHILD_ATTRS (   node)
Value:
((node) = \
child_rel->relids, \
child_rel->top_parent_relids))
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, Relids child_relids, Relids top_parent_relids)
Definition: appendinfo.c:488
Definition: pg_list.h:51
Definition: nodes.h:574

◆ CONSIDER_PATH_STARTUP_COST

#define CONSIDER_PATH_STARTUP_COST (   p)     ((p)->param_info == NULL ? (p)->parent->consider_startup : (p)->parent->consider_param_startup)

◆ FLAT_COPY_PATH

#define FLAT_COPY_PATH (   newnode,
  node,
  nodetype 
)
Value:
( (newnode) = makeNode(nodetype), \
memcpy((newnode), (node), sizeof(nodetype)) )
#define makeNode(_type_)
Definition: nodes.h:621

◆ REPARAMETERIZE_CHILD_PATH

#define REPARAMETERIZE_CHILD_PATH (   path)
Value:
do { \
(path) = reparameterize_path_by_child(root, (path), child_rel); \
if ((path) == NULL) \
return NULL; \
} while(0)
Path * reparameterize_path_by_child(PlannerInfo *root, Path *path, RelOptInfo *child_rel)
Definition: pathnode.c:3988

◆ REPARAMETERIZE_CHILD_PATH_LIST

#define REPARAMETERIZE_CHILD_PATH_LIST (   pathlist)
Value:
do { \
if ((pathlist) != NIL) \
{ \
(pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
child_rel); \
if ((pathlist) == NIL) \
return NULL; \
} \
} while(0)
static List * reparameterize_pathlist_by_child(PlannerInfo *root, List *pathlist, RelOptInfo *child_rel)
Definition: pathnode.c:4268
#define NIL
Definition: pg_list.h:65

◆ STD_FUZZ_FACTOR

#define STD_FUZZ_FACTOR   1.01

Definition at line 51 of file pathnode.c.

Enumeration Type Documentation

◆ PathCostComparison

Enumerator
COSTS_EQUAL 
COSTS_BETTER1 
COSTS_BETTER2 
COSTS_DIFFERENT 

Definition at line 38 of file pathnode.c.

39 {
40  COSTS_EQUAL, /* path costs are fuzzily equal */
41  COSTS_BETTER1, /* first path is cheaper than second */
42  COSTS_BETTER2, /* second path is cheaper than first */
43  COSTS_DIFFERENT /* neither path dominates the other on cost */
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

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
#define PATH_REQ_OUTER(path)
Definition: pathnodes.h:1213
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:200
double Cost
Definition: nodes.h:707

References clamp_row_est().

Referenced by create_limit_path(), and estimate_path_cost_size().

◆ append_startup_cost_compare()

static int append_startup_cost_compare ( const ListCell a,
const ListCell b 
)
static

Definition at line 1386 of file pathnode.c.

1387 {
1388  Path *path1 = (Path *) lfirst(a);
1389  Path *path2 = (Path *) lfirst(b);
1390  int cmp;
1391 
1392  cmp = compare_path_costs(path1, path2, STARTUP_COST);
1393  if (cmp != 0)
1394  return -cmp;
1395  return bms_compare(path1->parent->relids, path2->parent->relids);
1396 }
int bms_compare(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:147
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
Definition: pathnode.c:71
@ STARTUP_COST
Definition: pathnodes.h:36
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:747
RelOptInfo * parent
Definition: pathnodes.h:1194
Relids relids
Definition: pathnodes.h:682

References a, b, bms_compare(), cmp(), compare_path_costs(), lfirst, Path::parent, RelOptInfo::relids, and STARTUP_COST.

Referenced by create_append_path().

◆ append_total_cost_compare()

static int append_total_cost_compare ( const ListCell a,
const ListCell b 
)
static

Definition at line 1364 of file pathnode.c.

1365 {
1366  Path *path1 = (Path *) lfirst(a);
1367  Path *path2 = (Path *) lfirst(b);
1368  int cmp;
1369 
1370  cmp = compare_path_costs(path1, path2, TOTAL_COST);
1371  if (cmp != 0)
1372  return -cmp;
1373  return bms_compare(path1->parent->relids, path2->parent->relids);
1374 }
@ TOTAL_COST
Definition: pathnodes.h:36

References a, b, bms_compare(), cmp(), compare_path_costs(), lfirst, Path::parent, RelOptInfo::relids, and TOTAL_COST.

Referenced by create_append_path().

◆ 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:7140
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition: pathnode.c:2627
Path * subpath
Definition: pathnodes.h:1574
List * exprs
Definition: pathnodes.h:1122
QualCost cost
Definition: pathnodes.h:1124
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().

◆ 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
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
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 bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74

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 }

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 }

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().

◆ compare_path_costs_fuzzily()

static PathCostComparison compare_path_costs_fuzzily ( Path path1,
Path path2,
double  fuzz_factor 
)
static

Definition at line 166 of file pathnode.c.

167 {
168 #define CONSIDER_PATH_STARTUP_COST(p) \
169  ((p)->param_info == NULL ? (p)->parent->consider_startup : (p)->parent->consider_param_startup)
170 
171  /*
172  * Check total cost first since it's more likely to be different; many
173  * paths have zero startup cost.
174  */
175  if (path1->total_cost > path2->total_cost * fuzz_factor)
176  {
177  /* path1 fuzzily worse on total cost */
178  if (CONSIDER_PATH_STARTUP_COST(path1) &&
179  path2->startup_cost > path1->startup_cost * fuzz_factor)
180  {
181  /* ... but path2 fuzzily worse on startup, so DIFFERENT */
182  return COSTS_DIFFERENT;
183  }
184  /* else path2 dominates */
185  return COSTS_BETTER2;
186  }
187  if (path2->total_cost > path1->total_cost * fuzz_factor)
188  {
189  /* path2 fuzzily worse on total cost */
190  if (CONSIDER_PATH_STARTUP_COST(path2) &&
191  path1->startup_cost > path2->startup_cost * fuzz_factor)
192  {
193  /* ... but path1 fuzzily worse on startup, so DIFFERENT */
194  return COSTS_DIFFERENT;
195  }
196  /* else path1 dominates */
197  return COSTS_BETTER1;
198  }
199  /* fuzzily the same on total cost ... */
200  if (path1->startup_cost > path2->startup_cost * fuzz_factor)
201  {
202  /* ... but path1 fuzzily worse on startup, so path2 wins */
203  return COSTS_BETTER2;
204  }
205  if (path2->startup_cost > path1->startup_cost * fuzz_factor)
206  {
207  /* ... but path2 fuzzily worse on startup, so path1 wins */
208  return COSTS_BETTER1;
209  }
210  /* fuzzily the same on both costs */
211  return COSTS_EQUAL;
212 
213 #undef CONSIDER_PATH_STARTUP_COST
214 }
#define CONSIDER_PATH_STARTUP_COST(p)

References CONSIDER_PATH_STARTUP_COST, COSTS_BETTER1, COSTS_BETTER2, COSTS_DIFFERENT, COSTS_EQUAL, Path::startup_cost, and Path::total_cost.

Referenced by add_path().

◆ 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:2892
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:241
@ AGG_SORTED
Definition: nodes.h:808
@ T_Agg
Definition: nodes.h:82
static int list_length(const List *l)
Definition: pg_list.h:149
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:2475
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
@ RELOPT_BASEREL
Definition: pathnodes.h:642
#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
struct PathTarget * reltarget
Definition: pathnodes.h:693
RelOptKind reloptkind
Definition: pathnodes.h:679

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:1100
@ 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:956
@ 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:1144
@ 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:1623
@ 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 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
@ T_ForeignScan
Definition: nodes.h:71
Path * fdw_outerpath
Definition: pathnodes.h:1411
List * fdw_private
Definition: pathnodes.h:1412
Relids lateral_relids
Definition: pathnodes.h:707

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:1456
@ 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:417
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:2368
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:379
@ 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:3164
@ 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:121
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition: costsize.c:4640
@ 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:4181
@ 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:2228
@ 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:492
@ 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:2697
@ 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:2648
@ 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:3745
@ 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:1664
@ 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:3309
List * lappend(List *list, void *datum)
Definition: list.c:336
@ 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:1738
@ 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:1701

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:304
@ 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:227
@ 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:123
@ 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:1393
@ 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:1517
@ 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:1300
@ 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:1192
@ 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
@ RTE_SUBQUERY
Definition: parsenodes.h:999
@ RTE_RELATION
Definition: parsenodes.h:998
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
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:389
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition: selfuncs.c:3368
Query * subquery
Definition: parsenodes.h:1050
Index relid
Definition: pathnodes.h:710
struct Path * cheapest_unique_path
Definition: pathnodes.h:701
struct Path * cheapest_total_path
Definition: pathnodes.h:700
Cardinality rows
Definition: pathnodes.h:685
RTEKind rtekind
Definition: pathnodes.h:712
List * semi_rhs_exprs
Definition: pathnodes.h:2283
JoinType jointype
Definition: pathnodes.h:2276
Relids syn_righthand
Definition: pathnodes.h:2275
List * semi_operators
Definition: pathnodes.h:2282
Path * subpath
Definition: pathnodes.h:1560
List * uniq_exprs
Definition: pathnodes.h:1563
UniquePathMethod umethod
Definition: pathnodes.h:1561
List * in_operators
Definition: pathnodes.h:1562

References AGG_HASHED, Assert(), bms_equal(), RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, RelOptInfo::consider_parallel, cost_agg(), cost_sort(), cpu_operator_cost, estimate_num_groups(), get_hash_memory_limit(), GetMemoryChunkContext(), UniquePath::in_operators, JOIN_SEMI, SpecialJoinInfo::jointype, list_length(), makeNode, MemoryContextSwitchTo(), NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, UniquePath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, planner_rt_fetch, query_is_distinct_for(), query_supports_distinctness(), relation_has_unique_index_for(), RelOptInfo::relid, RelOptInfo::relids, RelOptInfo::reltarget, RelOptInfo::rows, Path::rows, RTE_RELATION, RTE_SUBQUERY, RelOptInfo::rtekind, SpecialJoinInfo::semi_can_btree, SpecialJoinInfo::semi_can_hash, SpecialJoinInfo::semi_operators, SpecialJoinInfo::semi_rhs_exprs, Path::startup_cost, subpath(), UniquePath::subpath, RangeTblEntry::subquery, SpecialJoinInfo::syn_righthand, T_Unique, Path::total_cost, translate_sub_tlist(), UniquePath::umethod, UniquePath::uniq_exprs, UNIQUE_PATH_HASH, UNIQUE_PATH_NOOP, UNIQUE_PATH_SORT, and work_mem.

Referenced by consider_parallel_nestloop(), hash_inner_and_outer(), join_is_legal(), match_unsorted_outer(), populate_joinrel_with_paths(), and sort_inner_and_outer().

◆ create_upper_unique_path()

UpperUniquePath* create_upper_unique_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
int  numCols,
double  numGroups 
)

Definition at line 3045 of file pathnode.c.

3050 {
3052 
3053  pathnode->path.pathtype = T_Unique;
3054  pathnode->path.parent = rel;
3055  /* Unique doesn't project, so use source path's pathtarget */
3056  pathnode->path.pathtarget = subpath->pathtarget;
3057  /* For now, assume we are above any joins, so no parameterization */
3058  pathnode->path.param_info = NULL;
3059  pathnode->path.parallel_aware = false;
3060  pathnode->path.parallel_safe = rel->consider_parallel &&
3061  subpath->parallel_safe;
3062  pathnode->path.parallel_workers = subpath->parallel_workers;
3063  /* Unique doesn't change the input ordering */
3064  pathnode->path.pathkeys = subpath->pathkeys;
3065 
3066  pathnode->subpath = subpath;
3067  pathnode->numkeys = numCols;
3068 
3069  /*
3070  * Charge one cpu_operator_cost per comparison per input tuple. We assume
3071  * all columns get compared at most of the tuples. (XXX probably this is
3072  * an overestimate.)
3073  */
3074  pathnode->path.startup_cost = subpath->startup_cost;
3075  pathnode->path.total_cost = subpath->total_cost +
3076  cpu_operator_cost * subpath->rows * numCols;
3077  pathnode->path.rows = numGroups;
3078 
3079  return pathnode;
3080 }

References RelOptInfo::consider_parallel, cpu_operator_cost, makeNode, UpperUniquePath::numkeys, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, UpperUniquePath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, Path::rows, Path::startup_cost, subpath(), UpperUniquePath::subpath, T_Unique, and Path::total_cost.

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

◆ create_valuesscan_path()

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

Definition at line 2071 of file pathnode.c.

2073 {
2074  Path *pathnode = makeNode(Path);
2075 
2076  pathnode->pathtype = T_ValuesScan;
2077  pathnode->parent = rel;
2078  pathnode->pathtarget = rel->reltarget;
2079  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2080  required_outer);
2081  pathnode->parallel_aware = false;
2082  pathnode->parallel_safe = rel->consider_parallel;
2083  pathnode->parallel_workers = 0;
2084  pathnode->pathkeys = NIL; /* result is always unordered */
2085 
2086  cost_valuesscan(pathnode, root, rel, pathnode->param_info);
2087 
2088  return pathnode;
2089 }
void cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1573
@ T_ValuesScan
Definition: nodes.h:66

References RelOptInfo::consider_parallel, cost_valuesscan(), 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_ValuesScan.

Referenced by set_values_pathlist().

◆ create_windowagg_path()

WindowAggPath* create_windowagg_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target,
List windowFuncs,
WindowClause winclause,
List qual,
bool  topwindow 
)

Definition at line 3400 of file pathnode.c.

3408 {
3409  WindowAggPath *pathnode = makeNode(WindowAggPath);
3410 
3411  /* qual can only be set for the topwindow */
3412  Assert(qual == NIL || topwindow);
3413 
3414  pathnode->path.pathtype = T_WindowAgg;
3415  pathnode->path.parent = rel;
3416  pathnode->path.pathtarget = target;
3417  /* For now, assume we are above any joins, so no parameterization */
3418  pathnode->path.param_info = NULL;
3419  pathnode->path.parallel_aware = false;
3420  pathnode->path.parallel_safe = rel->consider_parallel &&
3421  subpath->parallel_safe;
3422  pathnode->path.parallel_workers = subpath->parallel_workers;
3423  /* WindowAgg preserves the input sort order */
3424  pathnode->path.pathkeys = subpath->pathkeys;
3425 
3426  pathnode->subpath = subpath;
3427  pathnode->winclause = winclause;
3428  pathnode->qual = qual;
3429  pathnode->topwindow = topwindow;
3430 
3431  /*
3432  * For costing purposes, assume that there are no redundant partitioning
3433  * or ordering columns; it's not worth the trouble to deal with that
3434  * corner case here. So we just pass the unmodified list lengths to
3435  * cost_windowagg.
3436  */
3437  cost_windowagg(&pathnode->path, root,
3438  windowFuncs,
3439  list_length(winclause->partitionClause),
3440  list_length(winclause->orderClause),
3441  subpath->startup_cost,
3442  subpath->total_cost,
3443  subpath->rows);
3444 
3445  /* add tlist eval cost for each output row */
3446  pathnode->path.startup_cost += target->cost.startup;
3447  pathnode->path.total_cost += target->cost.startup +
3448  target->cost.per_tuple * pathnode->path.rows;
3449 
3450  return pathnode;
3451 }
void cost_windowagg(Path *path, PlannerInfo *root, List *windowFuncs, int numPartCols, int numOrderCols, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition: costsize.c:3090
@ T_WindowAgg
Definition: nodes.h:83
Path * subpath
Definition: pathnodes.h:1845
WindowClause * winclause
Definition: pathnodes.h:1846
List * partitionClause
Definition: parsenodes.h:1401
List * orderClause
Definition: parsenodes.h:1402

References Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cost_windowagg(), list_length(), makeNode, NIL, WindowClause::orderClause, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::param_info, Path::parent, WindowClause::partitionClause, WindowAggPath::path, Path::pathkeys, Path::pathtarget, Path::pathtype, QualCost::per_tuple, WindowAggPath::qual, Path::rows, QualCost::startup, Path::startup_cost, subpath(), WindowAggPath::subpath, T_WindowAgg, WindowAggPath::topwindow, Path::total_cost, and WindowAggPath::winclause.

Referenced by create_one_window_path().

◆ create_worktablescan_path()

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

Definition at line 2174 of file pathnode.c.

2176 {
2177  Path *pathnode = makeNode(Path);
2178 
2179  pathnode->pathtype = T_WorkTableScan;
2180  pathnode->parent = rel;
2181  pathnode->pathtarget = rel->reltarget;
2182  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2183  required_outer);
2184  pathnode->parallel_aware = false;
2185  pathnode->parallel_safe = rel->consider_parallel;
2186  pathnode->parallel_workers = 0;
2187  pathnode->pathkeys = NIL; /* result is always unordered */
2188 
2189  /* Cost is the same as for a regular CTE scan */
2190  cost_ctescan(pathnode, root, rel, pathnode->param_info);
2191 
2192  return pathnode;
2193 }
@ T_WorkTableScan
Definition: nodes.h:70

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_WorkTableScan.

Referenced by set_worktable_pathlist().

◆ reparameterize_path()

Path* reparameterize_path ( PlannerInfo root,
Path path,
Relids  required_outer,
double  loop_count 
)

Definition at line 3859 of file pathnode.c.

3862 {
3863  RelOptInfo *rel = path->parent;
3864 
3865  /* Can only increase, not decrease, path's parameterization */
3866  if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
3867  return NULL;
3868  switch (path->pathtype)
3869  {
3870  case T_SeqScan:
3871  return create_seqscan_path(root, rel, required_outer, 0);
3872  case T_SampleScan:
3873  return (Path *) create_samplescan_path(root, rel, required_outer);
3874  case T_IndexScan:
3875  case T_IndexOnlyScan:
3876  {
3877  IndexPath *ipath = (IndexPath *) path;
3878  IndexPath *newpath = makeNode(IndexPath);
3879 
3880  /*
3881  * We can't use create_index_path directly, and would not want
3882  * to because it would re-compute the indexqual conditions
3883  * which is wasted effort. Instead we hack things a bit:
3884  * flat-copy the path node, revise its param_info, and redo
3885  * the cost estimate.
3886  */
3887  memcpy(newpath, ipath, sizeof(IndexPath));
3888  newpath->path.param_info =
3889  get_baserel_parampathinfo(root, rel, required_outer);
3890  cost_index(newpath, root, loop_count, false);
3891  return (Path *) newpath;
3892  }
3893  case T_BitmapHeapScan:
3894  {
3895  BitmapHeapPath *bpath = (BitmapHeapPath *) path;
3896 
3897  return (Path *) create_bitmap_heap_path(root,
3898  rel,
3899  bpath->bitmapqual,
3900  required_outer,
3901  loop_count, 0);
3902  }
3903  case T_SubqueryScan:
3904  {
3905  SubqueryScanPath *spath = (SubqueryScanPath *) path;
3906 
3907  return (Path *) create_subqueryscan_path(root,
3908  rel,
3909  spath->subpath,
3910  spath->path.pathkeys,
3911  required_outer);
3912  }
3913  case T_Result:
3914  /* Supported only for RTE_RESULT scan paths */
3915  if (IsA(path, Path))
3916  return create_resultscan_path(root, rel, required_outer);
3917  break;
3918  case T_Append:
3919  {
3920  AppendPath *apath = (AppendPath *) path;
3921  List *childpaths = NIL;
3922  List *partialpaths = NIL;
3923  int i;
3924  ListCell *lc;
3925 
3926  /* Reparameterize the children */
3927  i = 0;
3928  foreach(lc, apath->subpaths)
3929  {
3930  Path *spath = (Path *) lfirst(lc);
3931 
3932  spath = reparameterize_path(root, spath,
3933  required_outer,
3934  loop_count);
3935  if (spath == NULL)
3936  return NULL;
3937  /* We have to re-split the regular and partial paths */
3938  if (i < apath->first_partial_path)
3939  childpaths = lappend(childpaths, spath);
3940  else
3941  partialpaths = lappend(partialpaths, spath);
3942  i++;
3943  }
3944  return (Path *)
3945  create_append_path(root, rel, childpaths, partialpaths,
3946  apath->path.pathkeys, required_outer,
3947  apath->path.parallel_workers,
3948  apath->path.parallel_aware,
3949  -1);
3950  }
3951  case T_Memoize:
3952  {
3953  MemoizePath *mpath = (MemoizePath *) path;
3954 
3955  return (Path *) create_memoize_path(root, rel,
3956  mpath->subpath,
3957  mpath->param_exprs,
3958  mpath->hash_operators,
3959  mpath->singlerow,
3960  mpath->binary_mode,
3961  mpath->calls);
3962  }
3963  default:
3964  break;
3965  }
3966  return NULL;
3967 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:315
int i
Definition: isn.c:73
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: pathnode.c:1244
Path * create_resultscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Definition: pathnode.c:2148
Path * create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Definition: pathnode.c:954
MemoizePath * create_memoize_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, double calls)
Definition: pathnode.c:1584
Path * reparameterize_path(PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
Definition: pathnode.c:3859
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, Relids required_outer)
Definition: pathnode.c:1991
Path * create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
Definition: pathnode.c:929
BitmapHeapPath * create_bitmap_heap_path(PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
Definition: pathnode.c:1046

References MemoizePath::binary_mode, BitmapHeapPath::bitmapqual, bms_is_subset(), MemoizePath::calls, cost_index(), create_append_path(), create_bitmap_heap_path(), create_memoize_path(), create_resultscan_path(), create_samplescan_path(), create_seqscan_path(), create_subqueryscan_path(), get_baserel_parampathinfo(), MemoizePath::hash_operators, i, IsA, lappend(), lfirst, makeNode, NIL, Path::parallel_aware, Path::parallel_workers, MemoizePath::param_exprs, Path::param_info, Path::parent, IndexPath::path, SubqueryScanPath::path, AppendPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, MemoizePath::singlerow, SubqueryScanPath::subpath, MemoizePath::subpath, AppendPath::subpaths, T_Append, T_BitmapHeapScan, T_IndexOnlyScan, T_IndexScan, T_Memoize, T_Result, T_SampleScan, T_SeqScan, and T_SubqueryScan.

Referenced by get_cheapest_parameterized_child_path().

◆ reparameterize_path_by_child()

Path* reparameterize_path_by_child ( PlannerInfo root,
Path path,
RelOptInfo child_rel 
)

Definition at line 3988 of file pathnode.c.

3990 {
3991 
3992 #define FLAT_COPY_PATH(newnode, node, nodetype) \
3993  ( (newnode) = makeNode(nodetype), \
3994  memcpy((newnode), (node), sizeof(nodetype)) )
3995 
3996 #define ADJUST_CHILD_ATTRS(node) \
3997  ((node) = \
3998  (List *) adjust_appendrel_attrs_multilevel(root, (Node *) (node), \
3999  child_rel->relids, \
4000  child_rel->top_parent_relids))
4001 
4002 #define REPARAMETERIZE_CHILD_PATH(path) \
4003 do { \
4004  (path) = reparameterize_path_by_child(root, (path), child_rel); \
4005  if ((path) == NULL) \
4006  return NULL; \
4007 } while(0)
4008 
4009 #define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
4010 do { \
4011  if ((pathlist) != NIL) \
4012  { \
4013  (pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
4014  child_rel); \
4015  if ((pathlist) == NIL) \
4016  return NULL; \
4017  } \
4018 } while(0)
4019 
4020  Path *new_path;
4021  ParamPathInfo *new_ppi;
4022  ParamPathInfo *old_ppi;
4023  Relids required_outer;
4024 
4025  /*
4026  * If the path is not parameterized by parent of the given relation, it
4027  * doesn't need reparameterization.
4028  */
4029  if (!path->param_info ||
4030  !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4031  return path;
4032 
4033  /*
4034  * If possible, reparameterize the given path, making a copy.
4035  *
4036  * This function is currently only applied to the inner side of a nestloop
4037  * join that is being partitioned by the partitionwise-join code. Hence,
4038  * we need only support path types that plausibly arise in that context.
4039  * (In particular, supporting sorted path types would be a waste of code
4040  * and cycles: even if we translated them here, they'd just lose in
4041  * subsequent cost comparisons.) If we do see an unsupported path type,
4042  * that just means we won't be able to generate a partitionwise-join plan
4043  * using that path type.
4044  */
4045  switch (nodeTag(path))
4046  {
4047  case T_Path:
4048  FLAT_COPY_PATH(new_path, path, Path);
4049  break;
4050 
4051  case T_IndexPath:
4052  {
4053  IndexPath *ipath;
4054 
4055  FLAT_COPY_PATH(ipath, path, IndexPath);
4057  new_path = (Path *) ipath;
4058  }
4059  break;
4060 
4061  case T_BitmapHeapPath:
4062  {
4063  BitmapHeapPath *bhpath;
4064 
4065  FLAT_COPY_PATH(bhpath, path, BitmapHeapPath);
4067  new_path = (Path *) bhpath;
4068  }
4069  break;
4070 
4071  case T_BitmapAndPath:
4072  {
4073  BitmapAndPath *bapath;
4074 
4075  FLAT_COPY_PATH(bapath, path, BitmapAndPath);
4077  new_path = (Path *) bapath;
4078  }
4079  break;
4080 
4081  case T_BitmapOrPath:
4082  {
4083  BitmapOrPath *bopath;
4084 
4085  FLAT_COPY_PATH(bopath, path, BitmapOrPath);
4087  new_path = (Path *) bopath;
4088  }
4089  break;
4090 
4091  case T_ForeignPath:
4092  {
4093  ForeignPath *fpath;
4095 
4096  FLAT_COPY_PATH(fpath, path, ForeignPath);
4097  if (fpath->fdw_outerpath)
4099 
4100  /* Hand over to FDW if needed. */
4101  rfpc_func =
4103  if (rfpc_func)
4104  fpath->fdw_private = rfpc_func(root, fpath->fdw_private,
4105  child_rel);
4106  new_path = (Path *) fpath;
4107  }
4108  break;
4109 
4110  case T_CustomPath:
4111  {
4112  CustomPath *cpath;
4113 
4114  FLAT_COPY_PATH(cpath, path, CustomPath);
4116  if (cpath->methods &&
4118  cpath->custom_private =
4120  cpath->custom_private,
4121  child_rel);
4122  new_path = (Path *) cpath;
4123  }
4124  break;
4125 
4126  case T_NestPath:
4127  {
4128  JoinPath *jpath;
4129  NestPath *npath;
4130 
4131  FLAT_COPY_PATH(npath, path, NestPath);
4132 
4133  jpath = (JoinPath *) npath;
4137  new_path = (Path *) npath;
4138  }
4139  break;
4140 
4141  case T_MergePath:
4142  {
4143  JoinPath *jpath;
4144  MergePath *mpath;
4145 
4146  FLAT_COPY_PATH(mpath, path, MergePath);
4147 
4148  jpath = (JoinPath *) mpath;
4153  new_path = (Path *) mpath;
4154  }
4155  break;
4156 
4157  case T_HashPath:
4158  {
4159  JoinPath *jpath;
4160  HashPath *hpath;
4161 
4162  FLAT_COPY_PATH(hpath, path, HashPath);
4163 
4164  jpath = (JoinPath *) hpath;
4169  new_path = (Path *) hpath;
4170  }
4171  break;
4172 
4173  case T_AppendPath:
4174  {
4175  AppendPath *apath;
4176 
4177  FLAT_COPY_PATH(apath, path, AppendPath);
4179  new_path = (Path *) apath;
4180  }
4181  break;
4182 
4183  case T_MemoizePath:
4184  {
4185  MemoizePath *mpath;
4186 
4187  FLAT_COPY_PATH(mpath, path, MemoizePath);
4189  new_path = (Path *) mpath;
4190  }
4191  break;
4192 
4193  case T_GatherPath:
4194  {
4195  GatherPath *gpath;
4196 
4197  FLAT_COPY_PATH(gpath, path, GatherPath);
4199  new_path = (Path *) gpath;
4200  }
4201  break;
4202 
4203  default:
4204 
4205  /* We don't know how to reparameterize this path. */
4206  return NULL;
4207  }
4208 
4209  /*
4210  * Adjust the parameterization information, which refers to the topmost
4211  * parent. The topmost parent can be multiple levels away from the given
4212  * child, hence use multi-level expression adjustment routines.
4213  */
4214  old_ppi = new_path->param_info;
4215  required_outer =
4217  child_rel->relids,
4218  child_rel->top_parent_relids);
4219 
4220  /* If we already have a PPI for this parameterization, just return it */
4221  new_ppi = find_param_path_info(new_path->parent, required_outer);
4222 
4223  /*
4224  * If not, build a new one and link it to the list of PPIs. For the same
4225  * reason as explained in mark_dummy_rel(), allocate new PPI in the same
4226  * context the given RelOptInfo is in.
4227  */
4228  if (new_ppi == NULL)
4229  {
4230  MemoryContext oldcontext;
4231  RelOptInfo *rel = path->parent;
4232 
4233  oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel));
4234 
4235  new_ppi = makeNode(