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, bool trivial_pathtarget, 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_restrictinfo, 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_restrictinfo, 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_restrictinfo, 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)
 
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, \
child_rel->top_parent))
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition: appendinfo.c:521
Definition: pg_list.h:54
Definition: nodes.h:129

◆ 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:155

◆ 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:4089

◆ 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:4385
#define NIL
Definition: pg_list.h:68

◆ 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:439
void pfree(void *pointer)
Definition: mcxt.c:1431
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
PathKeysComparison compare_pathkeys(List *keys1, List *keys2)
Definition: pathkeys.c:304
#define STD_FUZZ_FACTOR
Definition: pathnode.c:51
PathKeysComparison
Definition: paths.h:198
@ PATHKEYS_BETTER2
Definition: paths.h:201
@ PATHKEYS_BETTER1
Definition: paths.h:200
@ PATHKEYS_DIFFERENT
Definition: paths.h:202
#define lfirst(lc)
Definition: pg_list.h:172
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
List * pathkeys
Definition: pathnodes.h:1645
Cost total_cost
Definition: pathnodes.h:1642
bool parallel_safe
Definition: pathnodes.h:1635
bool consider_parallel
Definition: pathnodes.h:872
List * partial_pathlist
Definition: pathnodes.h:885

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:458
BMS_Comparison
Definition: bitmapset.h:61
@ BMS_SUBSET1
Definition: bitmapset.h:63
@ BMS_EQUAL
Definition: bitmapset.h:62
@ BMS_SUBSET2
Definition: bitmapset.h:64
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
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:1649
Cardinality rows
Definition: pathnodes.h:1640
List * pathlist
Definition: pathnodes.h:883

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_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:155
@ PATHKEYS_EQUAL
Definition: paths.h:199
Cost startup_cost
Definition: pathnodes.h:1641
bool consider_param_startup
Definition: pathnodes.h:870
bool consider_startup
Definition: pathnodes.h:868

References bms_equal(), compare_pathkeys(), RelOptInfo::consider_param_startup, RelOptInfo::consider_startup, lfirst, NIL, 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 3860 of file pathnode.c.

3865 {
3866  double input_rows = *rows;
3867  Cost input_startup_cost = *startup_cost;
3868  Cost input_total_cost = *total_cost;
3869 
3870  if (offset_est != 0)
3871  {
3872  double offset_rows;
3873 
3874  if (offset_est > 0)
3875  offset_rows = (double) offset_est;
3876  else
3877  offset_rows = clamp_row_est(input_rows * 0.10);
3878  if (offset_rows > *rows)
3879  offset_rows = *rows;
3880  if (input_rows > 0)
3881  *startup_cost +=
3882  (input_total_cost - input_startup_cost)
3883  * offset_rows / input_rows;
3884  *rows -= offset_rows;
3885  if (*rows < 1)
3886  *rows = 1;
3887  }
3888 
3889  if (count_est != 0)
3890  {
3891  double count_rows;
3892 
3893  if (count_est > 0)
3894  count_rows = (double) count_est;
3895  else
3896  count_rows = clamp_row_est(input_rows * 0.10);
3897  if (count_rows > *rows)
3898  count_rows = *rows;
3899  if (input_rows > 0)
3900  *total_cost = *startup_cost +
3901  (input_total_cost - input_startup_cost)
3902  * count_rows / input_rows;
3903  *rows = count_rows;
3904  if (*rows < 1)
3905  *rows = 1;
3906  }
3907 }
double clamp_row_est(double nrows)
Definition: costsize.c:203
double Cost
Definition: nodes.h:241

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 1399 of file pathnode.c.

1400 {
1401  Path *path1 = (Path *) lfirst(a);
1402  Path *path2 = (Path *) lfirst(b);
1403  int cmp;
1404 
1405  cmp = compare_path_costs(path1, path2, STARTUP_COST);
1406  if (cmp != 0)
1407  return -cmp;
1408  return bms_compare(path1->parent->relids, path2->parent->relids);
1409 }
int bms_compare(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:196
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:38
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743

References a, b, bms_compare(), cmp(), compare_path_costs(), lfirst, 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 1377 of file pathnode.c.

1378 {
1379  Path *path1 = (Path *) lfirst(a);
1380  Path *path2 = (Path *) lfirst(b);
1381  int cmp;
1382 
1383  cmp = compare_path_costs(path1, path2, TOTAL_COST);
1384  if (cmp != 0)
1385  return -cmp;
1386  return bms_compare(path1->parent->relids, path2->parent->relids);
1387 }
@ TOTAL_COST
Definition: pathnodes.h:38

References a, b, bms_compare(), cmp(), compare_path_costs(), lfirst, 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 2778 of file pathnode.c.

2782 {
2783  QualCost oldcost;
2784 
2785  /*
2786  * If given path can't project, we might need a Result node, so make a
2787  * separate ProjectionPath.
2788  */
2789  if (!is_projection_capable_path(path))
2790  return (Path *) create_projection_path(root, rel, path, target);
2791 
2792  /*
2793  * We can just jam the desired tlist into the existing path, being sure to
2794  * update its cost estimates appropriately.
2795  */
2796  oldcost = path->pathtarget->cost;
2797  path->pathtarget = target;
2798 
2799  path->startup_cost += target->cost.startup - oldcost.startup;
2800  path->total_cost += target->cost.startup - oldcost.startup +
2801  (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
2802 
2803  /*
2804  * If the path happens to be a Gather or GatherMerge path, we'd like to
2805  * arrange for the subpath to return the required target list so that
2806  * workers can help project. But if there is something that is not
2807  * parallel-safe in the target expressions, then we can't.
2808  */
2809  if ((IsA(path, GatherPath) || IsA(path, GatherMergePath)) &&
2810  is_parallel_safe(root, (Node *) target->exprs))
2811  {
2812  /*
2813  * We always use create_projection_path here, even if the subpath is
2814  * projection-capable, so as to avoid modifying the subpath in place.
2815  * It seems unlikely at present that there could be any other
2816  * references to the subpath, but better safe than sorry.
2817  *
2818  * Note that we don't change the parallel path's cost estimates; it
2819  * might be appropriate to do so, to reflect the fact that the bulk of
2820  * the target evaluation will happen in workers.
2821  */
2822  if (IsA(path, GatherPath))
2823  {
2824  GatherPath *gpath = (GatherPath *) path;
2825 
2826  gpath->subpath = (Path *)
2828  gpath->subpath->parent,
2829  gpath->subpath,
2830  target);
2831  }
2832  else
2833  {
2834  GatherMergePath *gmpath = (GatherMergePath *) path;
2835 
2836  gmpath->subpath = (Path *)
2838  gmpath->subpath->parent,
2839  gmpath->subpath,
2840  target);
2841  }
2842  }
2843  else if (path->parallel_safe &&
2844  !is_parallel_safe(root, (Node *) target->exprs))
2845  {
2846  /*
2847  * We're inserting a parallel-restricted target list into a path
2848  * currently marked parallel-safe, so we have to mark it as no longer
2849  * safe.
2850  */
2851  path->parallel_safe = false;
2852  }
2853 
2854  return path;
2855 }
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition: clauses.c:736
bool is_projection_capable_path(Path *path)
Definition: createplan.c:7186
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition: pathnode.c:2670
Path * subpath
Definition: pathnodes.h:2022
List * exprs
Definition: pathnodes.h:1513
QualCost cost
Definition: pathnodes.h:1519
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47

References PathTarget::cost, create_projection_path(), PathTarget::exprs, if(), is_parallel_safe(), is_projection_capable_path(), IsA, Path::parallel_safe, 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 2373 of file pathnode.c.

2377 {
2378  Relids required_outer;
2379 
2380  /* inner_path can require rels from outer path, but not vice versa */
2381  Assert(!bms_overlap(outer_paramrels, innerrelids));
2382  /* easy case if inner path is not parameterized */
2383  if (!inner_paramrels)
2384  return bms_copy(outer_paramrels);
2385  /* else, form the union ... */
2386  required_outer = bms_union(outer_paramrels, inner_paramrels);
2387  /* ... and remove any mention of now-satisfied outer rels */
2388  required_outer = bms_del_members(required_outer,
2389  outerrelids);
2390  return required_outer;
2391 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:264
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1174
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:595
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:135

References Assert(), bms_copy(), bms_del_members(), 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 2400 of file pathnode.c.

2401 {
2402  Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
2403  Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
2404  Relids innerrelids PG_USED_FOR_ASSERTS_ONLY;
2405  Relids outerrelids PG_USED_FOR_ASSERTS_ONLY;
2406  Relids required_outer;
2407 
2408  /*
2409  * Any parameterization of the input paths refers to topmost parents of
2410  * the relevant relations, because reparameterize_path_by_child() hasn't
2411  * been called yet. So we must consider topmost parents of the relations
2412  * being joined, too, while checking for disallowed parameterization
2413  * cases.
2414  */
2415  if (inner_path->parent->top_parent_relids)
2416  innerrelids = inner_path->parent->top_parent_relids;
2417  else
2418  innerrelids = inner_path->parent->relids;
2419 
2420  if (outer_path->parent->top_parent_relids)
2421  outerrelids = outer_path->parent->top_parent_relids;
2422  else
2423  outerrelids = outer_path->parent->relids;
2424 
2425  /* neither path can require rels from the other */
2426  Assert(!bms_overlap(outer_paramrels, innerrelids));
2427  Assert(!bms_overlap(inner_paramrels, outerrelids));
2428  /* form the union ... */
2429  required_outer = bms_union(outer_paramrels, inner_paramrels);
2430  /* we do not need an explicit test for empty; bms_union gets it right */
2431  return required_outer;
2432 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:171

References Assert(), bms_overlap(), bms_union(), PATH_REQ_OUTER, and PG_USED_FOR_ASSERTS_ONLY.

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 3140 of file pathnode.c.

3150 {
3151  AggPath *pathnode = makeNode(AggPath);
3152 
3153  pathnode->path.pathtype = T_Agg;
3154  pathnode->path.parent = rel;
3155  pathnode->path.pathtarget = target;
3156  /* For now, assume we are above any joins, so no parameterization */
3157  pathnode->path.param_info = NULL;
3158  pathnode->path.parallel_aware = false;
3159  pathnode->path.parallel_safe = rel->consider_parallel &&
3160  subpath->parallel_safe;
3161  pathnode->path.parallel_workers = subpath->parallel_workers;
3162 
3163  if (aggstrategy == AGG_SORTED)
3164  {
3165  /*
3166  * Attempt to preserve the order of the subpath. Additional pathkeys
3167  * may have been added in adjust_group_pathkeys_for_groupagg() to
3168  * support ORDER BY / DISTINCT aggregates. Pathkeys added there
3169  * belong to columns within the aggregate function, so we must strip
3170  * these additional pathkeys off as those columns are unavailable
3171  * above the aggregate node.
3172  */
3173  if (list_length(subpath->pathkeys) > root->num_groupby_pathkeys)
3174  pathnode->path.pathkeys = list_copy_head(subpath->pathkeys,
3175  root->num_groupby_pathkeys);
3176  else
3177  pathnode->path.pathkeys = subpath->pathkeys; /* preserves order */
3178  }
3179  else
3180  pathnode->path.pathkeys = NIL; /* output is unordered */
3181 
3182  pathnode->subpath = subpath;
3183 
3184  pathnode->aggstrategy = aggstrategy;
3185  pathnode->aggsplit = aggsplit;
3186  pathnode->numGroups = numGroups;
3187  pathnode->transitionSpace = aggcosts ? aggcosts->transitionSpace : 0;
3188  pathnode->groupClause = groupClause;
3189  pathnode->qual = qual;
3190 
3191  cost_agg(&pathnode->path, root,
3192  aggstrategy, aggcosts,
3193  list_length(groupClause), numGroups,
3194  qual,
3195  subpath->startup_cost, subpath->total_cost,
3196  subpath->rows, subpath->pathtarget->width);
3197 
3198  /* add tlist eval cost for each output row */
3199  pathnode->path.startup_cost += target->cost.startup;
3200  pathnode->path.total_cost += target->cost.startup +
3201  target->cost.per_tuple * pathnode->path.rows;
3202 
3203  return pathnode;
3204 }
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:2651
List * list_copy_head(const List *oldlist, int len)
Definition: list.c:1593
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:241
@ AGG_SORTED
Definition: nodes.h:344
static int list_length(const List *l)
Definition: pg_list.h:152
Size transitionSpace
Definition: pathnodes.h:62
Path * subpath
Definition: pathnodes.h:2234
Cardinality numGroups
Definition: pathnodes.h:2237
AggSplit aggsplit
Definition: pathnodes.h:2236
List * groupClause
Definition: pathnodes.h:2239
uint64 transitionSpace
Definition: pathnodes.h:2238
AggStrategy aggstrategy
Definition: pathnodes.h:2235
Path path
Definition: pathnodes.h:2233
List * qual
Definition: pathnodes.h:2240
NodeTag pathtype
Definition: pathnodes.h:1606
int parallel_workers
Definition: pathnodes.h:1637
bool parallel_aware
Definition: pathnodes.h:1633
int num_groupby_pathkeys
Definition: pathnodes.h:392

References AGG_SORTED, AggPath::aggsplit, AggPath::aggstrategy, RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), AggPath::groupClause, list_copy_head(), list_length(), makeNode, NIL, PlannerInfo::num_groupby_pathkeys, AggPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, AggPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, AggPath::qual, Path::rows, QualCost::startup, Path::startup_cost, subpath(), AggPath::subpath, 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 1246 of file pathnode.c.

1252 {
1253  AppendPath *pathnode = makeNode(AppendPath);
1254  ListCell *l;
1255 
1256  Assert(!parallel_aware || parallel_workers > 0);
1257 
1258  pathnode->path.pathtype = T_Append;
1259  pathnode->path.parent = rel;
1260  pathnode->path.pathtarget = rel->reltarget;
1261 
1262  /*
1263  * If this is for a baserel (not a join or non-leaf partition), we prefer
1264  * to apply get_baserel_parampathinfo to construct a full ParamPathInfo
1265  * for the path. This supports building a Memoize path atop this path,
1266  * and if this is a partitioned table the info may be useful for run-time
1267  * pruning (cf make_partition_pruneinfo()).
1268  *
1269  * However, if we don't have "root" then that won't work and we fall back
1270  * on the simpler get_appendrel_parampathinfo. There's no point in doing
1271  * the more expensive thing for a dummy path, either.
1272  */
1273  if (rel->reloptkind == RELOPT_BASEREL && root && subpaths != NIL)
1274  pathnode->path.param_info = get_baserel_parampathinfo(root,
1275  rel,
1276  required_outer);
1277  else
1278  pathnode->path.param_info = get_appendrel_parampathinfo(rel,
1279  required_outer);
1280 
1281  pathnode->path.parallel_aware = parallel_aware;
1282  pathnode->path.parallel_safe = rel->consider_parallel;
1283  pathnode->path.parallel_workers = parallel_workers;
1284  pathnode->path.pathkeys = pathkeys;
1285 
1286  /*
1287  * For parallel append, non-partial paths are sorted by descending total
1288  * costs. That way, the total time to finish all non-partial paths is
1289  * minimized. Also, the partial paths are sorted by descending startup
1290  * costs. There may be some paths that require to do startup work by a
1291  * single worker. In such case, it's better for workers to choose the
1292  * expensive ones first, whereas the leader should choose the cheapest
1293  * startup plan.
1294  */
1295  if (pathnode->path.parallel_aware)
1296  {
1297  /*
1298  * We mustn't fiddle with the order of subpaths when the Append has
1299  * pathkeys. The order they're listed in is critical to keeping the
1300  * pathkeys valid.
1301  */
1302  Assert(pathkeys == NIL);
1303 
1305  list_sort(partial_subpaths, append_startup_cost_compare);
1306  }
1307  pathnode->first_partial_path = list_length(subpaths);
1308  pathnode->subpaths = list_concat(subpaths, partial_subpaths);
1309 
1310  /*
1311  * Apply query-wide LIMIT if known and path is for sole base relation.
1312  * (Handling this at this low level is a bit klugy.)
1313  */
1314  if (root != NULL && bms_equal(rel->relids, root->all_query_rels))
1315  pathnode->limit_tuples = root->limit_tuples;
1316  else
1317  pathnode->limit_tuples = -1.0;
1318 
1319  foreach(l, pathnode->subpaths)
1320  {
1321  Path *subpath = (Path *) lfirst(l);
1322 
1323  pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1324  subpath->parallel_safe;
1325 
1326  /* All child paths must have same parameterization */
1327  Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
1328  }
1329 
1330  Assert(!parallel_aware || pathnode->path.parallel_safe);
1331 
1332  /*
1333  * If there's exactly one child path then the output of the Append is
1334  * necessarily ordered the same as the child's, so we can inherit the
1335  * child's pathkeys if any, overriding whatever the caller might've said.
1336  * Furthermore, if the child's parallel awareness matches the Append's,
1337  * then the Append is a no-op and will be discarded later (in setrefs.c).
1338  * Then we can inherit the child's size and cost too, effectively charging
1339  * zero for the Append. Otherwise, we must do the normal costsize
1340  * calculation.
1341  */
1342  if (list_length(pathnode->subpaths) == 1)
1343  {
1344  Path *child = (Path *) linitial(pathnode->subpaths);
1345 
1346  if (child->parallel_aware == parallel_aware)
1347  {
1348  pathnode->path.rows = child->rows;
1349  pathnode->path.startup_cost = child->startup_cost;
1350  pathnode->path.total_cost = child->total_cost;
1351  }
1352  else
1353  cost_append(pathnode);
1354  /* Must do this last, else cost_append complains */
1355  pathnode->path.pathkeys = child->pathkeys;
1356  }
1357  else
1358  cost_append(pathnode);
1359 
1360  /* If the caller provided a row estimate, override the computed value. */
1361  if (rows >= 0)
1362  pathnode->path.rows = rows;
1363 
1364  return pathnode;
1365 }
void cost_append(AppendPath *apath)
Definition: costsize.c:2232
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
static int append_startup_cost_compare(const ListCell *a, const ListCell *b)
Definition: pathnode.c:1399
static int append_total_cost_compare(const ListCell *a, const ListCell *b)
Definition: pathnode.c:1377
@ RELOPT_BASEREL
Definition: pathnodes.h:812
#define linitial(l)
Definition: pg_list.h:178
ParamPathInfo * get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
Definition: relnode.c:1550
ParamPathInfo * get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
Definition: relnode.c:1849
int first_partial_path
Definition: pathnodes.h:1914
Cardinality limit_tuples
Definition: pathnodes.h:1915
List * subpaths
Definition: pathnodes.h:1912
Relids all_query_rels
Definition: pathnodes.h:266
Cardinality limit_tuples
Definition: pathnodes.h:480
Relids relids
Definition: pathnodes.h:856
struct PathTarget * reltarget
Definition: pathnodes.h:878
RelOptKind reloptkind
Definition: pathnodes.h:850

References PlannerInfo::all_query_rels, 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(), 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, AppendPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, RelOptInfo::relids, RELOPT_BASEREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, Path::rows, Path::startup_cost, subpath(), AppendPath::subpaths, 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 1077 of file pathnode.c.

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

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, BitmapAndPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, and RelOptInfo::reltarget.

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 1044 of file pathnode.c.

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

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

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 1129 of file pathnode.c.

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

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, BitmapOrPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, and RelOptInfo::reltarget.

Referenced by generate_bitmap_or_paths().

◆ create_ctescan_path()

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

Definition at line 2120 of file pathnode.c.

2121 {
2122  Path *pathnode = makeNode(Path);
2123 
2124  pathnode->pathtype = T_CteScan;
2125  pathnode->parent = rel;
2126  pathnode->pathtarget = rel->reltarget;
2127  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2128  required_outer);
2129  pathnode->parallel_aware = false;
2130  pathnode->parallel_safe = rel->consider_parallel;
2131  pathnode->parallel_workers = 0;
2132  pathnode->pathkeys = NIL; /* XXX for now, result is always unordered */
2133 
2134  cost_ctescan(pathnode, root, rel, pathnode->param_info);
2135 
2136  return pathnode;
2137 }
void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1699

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

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_restrictinfo,
List fdw_private 
)

Definition at line 2276 of file pathnode.c.

2284 {
2285  ForeignPath *pathnode = makeNode(ForeignPath);
2286 
2287  /*
2288  * We should use get_joinrel_parampathinfo to handle parameterized paths,
2289  * but the API of this function doesn't support it, and existing
2290  * extensions aren't yet trying to build such paths anyway. For the
2291  * moment just throw an error if someone tries it; eventually we should
2292  * revisit this.
2293  */
2294  if (!bms_is_empty(required_outer) || !bms_is_empty(rel->lateral_relids))
2295  elog(ERROR, "parameterized foreign joins are not supported yet");
2296 
2297  pathnode->path.pathtype = T_ForeignScan;
2298  pathnode->path.parent = rel;
2299  pathnode->path.pathtarget = target ? target : rel->reltarget;
2300  pathnode->path.param_info = NULL; /* XXX see above */
2301  pathnode->path.parallel_aware = false;
2302  pathnode->path.parallel_safe = rel->consider_parallel;
2303  pathnode->path.parallel_workers = 0;
2304  pathnode->path.rows = rows;
2305  pathnode->path.startup_cost = startup_cost;
2306  pathnode->path.total_cost = total_cost;
2307  pathnode->path.pathkeys = pathkeys;
2308 
2309  pathnode->fdw_outerpath = fdw_outerpath;
2310  pathnode->fdw_restrictinfo = fdw_restrictinfo;
2311  pathnode->fdw_private = fdw_private;
2312 
2313  return pathnode;
2314 }
#define bms_is_empty(a)
Definition: bitmapset.h:105
#define ERROR
Definition: elog.h:39
Path * fdw_outerpath
Definition: pathnodes.h:1850
List * fdw_restrictinfo
Definition: pathnodes.h:1851
List * fdw_private
Definition: pathnodes.h:1852
Relids lateral_relids
Definition: pathnodes.h:898

References bms_is_empty, RelOptInfo::consider_parallel, elog(), ERROR, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, ForeignPath::fdw_restrictinfo, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ForeignPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, 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_restrictinfo,
List fdw_private 
)

Definition at line 2328 of file pathnode.c.

2335 {
2336  ForeignPath *pathnode = makeNode(ForeignPath);
2337 
2338  /*
2339  * Upper relations should never have any lateral references, since joining
2340  * is complete.
2341  */
2343 
2344  pathnode->path.pathtype = T_ForeignScan;
2345  pathnode->path.parent = rel;
2346  pathnode->path.pathtarget = target ? target : rel->reltarget;
2347  pathnode->path.param_info = NULL;
2348  pathnode->path.parallel_aware = false;
2349  pathnode->path.parallel_safe = rel->consider_parallel;
2350  pathnode->path.parallel_workers = 0;
2351  pathnode->path.rows = rows;
2352  pathnode->path.startup_cost = startup_cost;
2353  pathnode->path.total_cost = total_cost;
2354  pathnode->path.pathkeys = pathkeys;
2355 
2356  pathnode->fdw_outerpath = fdw_outerpath;
2357  pathnode->fdw_restrictinfo = fdw_restrictinfo;
2358  pathnode->fdw_private = fdw_private;
2359 
2360  return pathnode;
2361 }

References Assert(), bms_is_empty, RelOptInfo::consider_parallel, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, ForeignPath::fdw_restrictinfo, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ForeignPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, 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_restrictinfo,
List fdw_private 
)

Definition at line 2230 of file pathnode.c.

2238 {
2239  ForeignPath *pathnode = makeNode(ForeignPath);
2240 
2241  /* Historically some FDWs were confused about when to use this */
2242  Assert(IS_SIMPLE_REL(rel));
2243 
2244  pathnode->path.pathtype = T_ForeignScan;
2245  pathnode->path.parent = rel;
2246  pathnode->path.pathtarget = target ? target : rel->reltarget;
2247  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
2248  required_outer);
2249  pathnode->path.parallel_aware = false;
2250  pathnode->path.parallel_safe = rel->consider_parallel;
2251  pathnode->path.parallel_workers = 0;
2252  pathnode->path.rows = rows;
2253  pathnode->path.startup_cost = startup_cost;
2254  pathnode->path.total_cost = total_cost;
2255  pathnode->path.pathkeys = pathkeys;
2256 
2257  pathnode->fdw_outerpath = fdw_outerpath;
2258  pathnode->fdw_restrictinfo = fdw_restrictinfo;
2259  pathnode->fdw_private = fdw_private;
2260 
2261  return pathnode;
2262 }
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:824

References Assert(), RelOptInfo::consider_parallel, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, ForeignPath::fdw_restrictinfo, get_baserel_parampathinfo(), IS_SIMPLE_REL, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ForeignPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, 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 2042 of file pathnode.c.

2044 {
2045  Path *pathnode = makeNode(Path);
2046 
2047  pathnode->pathtype = T_FunctionScan;
2048  pathnode->parent = rel;
2049  pathnode->pathtarget = rel->reltarget;
2050  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2051  required_outer);
2052  pathnode->parallel_aware = false;
2053  pathnode->parallel_safe = rel->consider_parallel;
2054  pathnode->parallel_workers = 0;
2055  pathnode->pathkeys = pathkeys;
2056 
2057  cost_functionscan(pathnode, root, rel, pathnode->param_info);
2058 
2059  return pathnode;
2060 }
void cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1532

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

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 1877 of file pathnode.c.

1880 {
1882  Cost input_startup_cost = 0;
1883  Cost input_total_cost = 0;
1884 
1885  Assert(subpath->parallel_safe);
1886  Assert(pathkeys);
1887 
1888  pathnode->path.pathtype = T_GatherMerge;
1889  pathnode->path.parent = rel;
1890  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1891  required_outer);
1892  pathnode->path.parallel_aware = false;
1893 
1894  pathnode->subpath = subpath;
1895  pathnode->num_workers = subpath->parallel_workers;
1896  pathnode->path.pathkeys = pathkeys;
1897  pathnode->path.pathtarget = target ? target : rel->reltarget;
1898  pathnode->path.rows += subpath->rows;
1899 
1900  if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
1901  {
1902  /* Subpath is adequately ordered, we won't need to sort it */
1903  input_startup_cost += subpath->startup_cost;
1904  input_total_cost += subpath->total_cost;
1905  }
1906  else
1907  {
1908  /* We'll need to insert a Sort node, so include cost for that */
1909  Path sort_path; /* dummy for result of cost_sort */
1910 
1911  cost_sort(&sort_path,
1912  root,
1913  pathkeys,
1914  subpath->total_cost,
1915  subpath->rows,
1916  subpath->pathtarget->width,
1917  0.0,
1918  work_mem,
1919  -1);
1920  input_startup_cost += sort_path.startup_cost;
1921  input_total_cost += sort_path.total_cost;
1922  }
1923 
1924  cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
1925  input_startup_cost, input_total_cost, rows);
1926 
1927  return pathnode;
1928 }
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:475
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:2125
int work_mem
Definition: globals.c:128
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition: pathkeys.c:343

References Assert(), cost_gather_merge(), cost_sort(), get_baserel_parampathinfo(), makeNode, GatherMergePath::num_workers, Path::parallel_aware, GatherMergePath::path, Path::pathkeys, pathkeys_contained_in(), Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, subpath(), GatherMergePath::subpath, 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 1968 of file pathnode.c.

1970 {
1971  GatherPath *pathnode = makeNode(GatherPath);
1972 
1973  Assert(subpath->parallel_safe);
1974 
1975  pathnode->path.pathtype = T_Gather;
1976  pathnode->path.parent = rel;
1977  pathnode->path.pathtarget = target;
1978  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1979  required_outer);
1980  pathnode->path.parallel_aware = false;
1981  pathnode->path.parallel_safe = false;
1982  pathnode->path.parallel_workers = 0;
1983  pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1984 
1985  pathnode->subpath = subpath;
1986  pathnode->num_workers = subpath->parallel_workers;
1987  pathnode->single_copy = false;
1988 
1989  if (pathnode->num_workers == 0)
1990  {
1991  pathnode->path.pathkeys = subpath->pathkeys;
1992  pathnode->num_workers = 1;
1993  pathnode->single_copy = true;
1994  }
1995 
1996  cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1997 
1998  return pathnode;
1999 }
void cost_gather(GatherPath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, double *rows)
Definition: costsize.c:437
bool single_copy
Definition: pathnodes.h:2023
int num_workers
Definition: pathnodes.h:2024

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

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 3029 of file pathnode.c.

3035 {
3036  GroupPath *pathnode = makeNode(GroupPath);
3037  PathTarget *target = rel->reltarget;
3038 
3039  pathnode->path.pathtype = T_Group;
3040  pathnode->path.parent = rel;
3041  pathnode->path.pathtarget = target;
3042  /* For now, assume we are above any joins, so no parameterization */
3043  pathnode->path.param_info = NULL;
3044  pathnode->path.parallel_aware = false;
3045  pathnode->path.parallel_safe = rel->consider_parallel &&
3046  subpath->parallel_safe;
3047  pathnode->path.parallel_workers = subpath->parallel_workers;
3048  /* Group doesn't change sort ordering */
3049  pathnode->path.pathkeys = subpath->pathkeys;
3050 
3051  pathnode->subpath = subpath;
3052 
3053  pathnode->groupClause = groupClause;
3054  pathnode->qual = qual;
3055 
3056  cost_group(&pathnode->path, root,
3057  list_length(groupClause),
3058  numGroups,
3059  qual,
3060  subpath->startup_cost, subpath->total_cost,
3061  subpath->rows);
3062 
3063  /* add tlist eval cost for each output row */
3064  pathnode->path.startup_cost += target->cost.startup;
3065  pathnode->path.total_cost += target->cost.startup +
3066  target->cost.per_tuple * pathnode->path.rows;
3067 
3068  return pathnode;
3069 }
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
List * qual
Definition: pathnodes.h:2208
List * groupClause
Definition: pathnodes.h:2207
Path * subpath
Definition: pathnodes.h:2206
Path path
Definition: pathnodes.h:2205

References RelOptInfo::consider_parallel, PathTarget::cost, cost_group(), GroupPath::groupClause, list_length(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, GroupPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, GroupPath::qual, RelOptInfo::reltarget, Path::rows, QualCost::startup, Path::startup_cost, subpath(), GroupPath::subpath, 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 1520 of file pathnode.c.

1522 {
1524 
1525  pathnode->path.pathtype = T_Result;
1526  pathnode->path.parent = rel;
1527  pathnode->path.pathtarget = target;
1528  pathnode->path.param_info = NULL; /* there are no other rels... */
1529  pathnode->path.parallel_aware = false;
1530  pathnode->path.parallel_safe = rel->consider_parallel;
1531  pathnode->path.parallel_workers = 0;
1532  pathnode->path.pathkeys = NIL;
1533  pathnode->quals = havingqual;
1534 
1535  /*
1536  * We can't quite use cost_resultscan() because the quals we want to
1537  * account for are not baserestrict quals of the rel. Might as well just
1538  * hack it here.
1539  */
1540  pathnode->path.rows = 1;
1541  pathnode->path.startup_cost = target->cost.startup;
1542  pathnode->path.total_cost = target->cost.startup +
1543  cpu_tuple_cost + target->cost.per_tuple;
1544 
1545  /*
1546  * Add cost of qual, if any --- but we ignore its selectivity, since our
1547  * rowcount estimate should be 1 no matter what the qual is.
1548  */
1549  if (havingqual)
1550  {
1551  QualCost qual_cost;
1552 
1553  cost_qual_eval(&qual_cost, havingqual, root);
1554  /* havingqual is evaluated once at startup */
1555  pathnode->path.startup_cost += qual_cost.startup + qual_cost.per_tuple;
1556  pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
1557  }
1558 
1559  return pathnode;
1560 }
double cpu_tuple_cost
Definition: costsize.c:122
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition: costsize.c:4641

References RelOptInfo::consider_parallel, PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, GroupResultPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, GroupResultPath::quals, Path::rows, QualCost::startup, Path::startup_cost, 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 
)

Definition at line 3222 of file pathnode.c.

3229 {
3231  PathTarget *target = rel->reltarget;
3232  ListCell *lc;
3233  bool is_first = true;
3234  bool is_first_sort = true;
3235 
3236  /* The topmost generated Plan node will be an Agg */
3237  pathnode->path.pathtype = T_Agg;
3238  pathnode->path.parent = rel;
3239  pathnode->path.pathtarget = target;
3240  pathnode->path.param_info = subpath->param_info;
3241  pathnode->path.parallel_aware = false;
3242  pathnode->path.parallel_safe = rel->consider_parallel &&
3243  subpath->parallel_safe;
3244  pathnode->path.parallel_workers = subpath->parallel_workers;
3245  pathnode->subpath = subpath;
3246 
3247  /*
3248  * Simplify callers by downgrading AGG_SORTED to AGG_PLAIN, and AGG_MIXED
3249  * to AGG_HASHED, here if possible.
3250  */
3251  if (aggstrategy == AGG_SORTED &&
3252  list_length(rollups) == 1 &&
3253  ((RollupData *) linitial(rollups))->groupClause == NIL)
3254  aggstrategy = AGG_PLAIN;
3255 
3256  if (aggstrategy == AGG_MIXED &&
3257  list_length(rollups) == 1)
3258  aggstrategy = AGG_HASHED;
3259 
3260  /*
3261  * Output will be in sorted order by group_pathkeys if, and only if, there
3262  * is a single rollup operation on a non-empty list of grouping
3263  * expressions.
3264  */
3265  if (aggstrategy == AGG_SORTED && list_length(rollups) == 1)
3266  pathnode->path.pathkeys = root->group_pathkeys;
3267  else
3268  pathnode->path.pathkeys = NIL;
3269 
3270  pathnode->aggstrategy = aggstrategy;
3271  pathnode->rollups = rollups;
3272  pathnode->qual = having_qual;
3273  pathnode->transitionSpace = agg_costs ? agg_costs->transitionSpace : 0;
3274 
3275  Assert(rollups != NIL);
3276  Assert(aggstrategy != AGG_PLAIN || list_length(rollups) == 1);
3277  Assert(aggstrategy != AGG_MIXED || list_length(rollups) > 1);
3278 
3279  foreach(lc, rollups)
3280  {
3281  RollupData *rollup = lfirst(lc);
3282  List *gsets = rollup->gsets;
3283  int numGroupCols = list_length(linitial(gsets));
3284 
3285  /*
3286  * In AGG_SORTED or AGG_PLAIN mode, the first rollup takes the
3287  * (already-sorted) input, and following ones do their own sort.
3288  *
3289  * In AGG_HASHED mode, there is one rollup for each grouping set.
3290  *
3291  * In AGG_MIXED mode, the first rollups are hashed, the first
3292  * non-hashed one takes the (already-sorted) input, and following ones
3293  * do their own sort.
3294  */
3295  if (is_first)
3296  {
3297  cost_agg(&pathnode->path, root,
3298  aggstrategy,
3299  agg_costs,
3300  numGroupCols,
3301  rollup->numGroups,
3302  having_qual,
3303  subpath->startup_cost,
3304  subpath->total_cost,
3305  subpath->rows,
3306  subpath->pathtarget->width);
3307  is_first = false;
3308  if (!rollup->is_hashed)
3309  is_first_sort = false;
3310  }
3311  else
3312  {
3313  Path sort_path; /* dummy for result of cost_sort */
3314  Path agg_path; /* dummy for result of cost_agg */
3315 
3316  if (rollup->is_hashed || is_first_sort)
3317  {
3318  /*
3319  * Account for cost of aggregation, but don't charge input
3320  * cost again
3321  */
3322  cost_agg(&agg_path, root,
3323  rollup->is_hashed ? AGG_HASHED : AGG_SORTED,
3324  agg_costs,
3325  numGroupCols,
3326  rollup->numGroups,
3327  having_qual,
3328  0.0, 0.0,
3329  subpath->rows,
3330  subpath->pathtarget->width);
3331  if (!rollup->is_hashed)
3332  is_first_sort = false;
3333  }
3334  else
3335  {
3336  /* Account for cost of sort, but don't charge input cost again */
3337  cost_sort(&sort_path, root, NIL,
3338  0.0,
3339  subpath->rows,
3340  subpath->pathtarget->width,
3341  0.0,
3342  work_mem,
3343  -1.0);
3344 
3345  /* Account for cost of aggregation */
3346 
3347  cost_agg(&agg_path, root,
3348  AGG_SORTED,
3349  agg_costs,
3350  numGroupCols,
3351  rollup->numGroups,
3352  having_qual,
3353  sort_path.startup_cost,
3354  sort_path.total_cost,
3355  sort_path.rows,
3356  subpath->pathtarget->width);
3357  }
3358 
3359  pathnode->path.total_cost += agg_path.total_cost;
3360  pathnode->path.rows += agg_path.rows;
3361  }
3362  }
3363 
3364  /* add tlist eval cost for each output row */
3365  pathnode->path.startup_cost += target->cost.startup;
3366  pathnode->path.total_cost += target->cost.startup +
3367  target->cost.per_tuple * pathnode->path.rows;
3368 
3369  return pathnode;
3370 }
@ AGG_HASHED
Definition: nodes.h:345
@ AGG_MIXED
Definition: nodes.h:346
@ AGG_PLAIN
Definition: nodes.h:343
uint64 transitionSpace
Definition: pathnodes.h:2280
AggStrategy aggstrategy
Definition: pathnodes.h:2277
List * group_pathkeys
Definition: pathnodes.h:385
Cardinality numGroups
Definition: pathnodes.h:2264
List * gsets
Definition: pathnodes.h:2262
bool is_hashed
Definition: pathnodes.h:2266

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, GroupingSetsPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, GroupingSetsPath::qual, RelOptInfo::reltarget, GroupingSetsPath::rollups, Path::rows, QualCost::startup, Path::startup_cost, subpath(), GroupingSetsPath::subpath, 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 2604 of file pathnode.c.

2615 {
2616  HashPath *pathnode = makeNode(HashPath);
2617 
2618  pathnode->jpath.path.pathtype = T_HashJoin;
2619  pathnode->jpath.path.parent = joinrel;
2620  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2621  pathnode->jpath.path.param_info =
2623  joinrel,
2624  outer_path,
2625  inner_path,
2626  extra->sjinfo,
2627  required_outer,
2628  &restrict_clauses);
2629  pathnode->jpath.path.parallel_aware =
2630  joinrel->consider_parallel && parallel_hash;
2631  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2632  outer_path->parallel_safe && inner_path->parallel_safe;
2633  /* This is a foolish way to estimate parallel_workers, but for now... */
2634  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2635 
2636  /*
2637  * A hashjoin never has pathkeys, since its output ordering is
2638  * unpredictable due to possible batching. XXX If the inner relation is
2639  * small enough, we could instruct the executor that it must not batch,
2640  * and then we could assume that the output inherits the outer relation's
2641  * ordering, which might save a sort step. However there is considerable
2642  * downside if our estimate of the inner relation size is badly off. For
2643  * the moment we don't risk it. (Note also that if we wanted to take this
2644  * seriously, joinpath.c would have to consider many more paths for the
2645  * outer rel than it does now.)
2646  */
2647  pathnode->jpath.path.pathkeys = NIL;
2648  pathnode->jpath.jointype = jointype;
2649  pathnode->jpath.inner_unique = extra->inner_unique;
2650  pathnode->jpath.outerjoinpath = outer_path;
2651  pathnode->jpath.innerjoinpath = inner_path;
2652  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2653  pathnode->path_hashclauses = hashclauses;
2654  /* final_cost_hashjoin will fill in pathnode->num_batches */
2655 
2656  final_cost_hashjoin(root, pathnode, workspace, extra);
2657 
2658  return pathnode;
2659 }
void final_cost_hashjoin(PlannerInfo *root, HashPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:4182
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:1652
List * path_hashclauses
Definition: pathnodes.h:2132
JoinPath jpath
Definition: pathnodes.h:2131
SpecialJoinInfo * sjinfo
Definition: pathnodes.h:3207
Path * outerjoinpath
Definition: pathnodes.h:2054
Path * innerjoinpath
Definition: pathnodes.h:2055
JoinType jointype
Definition: pathnodes.h:2049
bool inner_unique
Definition: pathnodes.h:2051
List * joinrestrictinfo
Definition: pathnodes.h:2057

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_safe, Path::parallel_workers, HashPath::path_hashclauses, RelOptInfo::reltarget, and JoinPathExtraData::sjinfo.

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 2936 of file pathnode.c.

2942 {
2944  SortPath *pathnode = &sort->spath;
2945 
2946  pathnode->path.pathtype = T_IncrementalSort;
2947  pathnode->path.parent = rel;
2948  /* Sort doesn't project, so use source path's pathtarget */
2949  pathnode->path.pathtarget = subpath->pathtarget;
2950  /* For now, assume we are above any joins, so no parameterization */
2951  pathnode->path.param_info = NULL;
2952  pathnode->path.parallel_aware = false;
2953  pathnode->path.parallel_safe = rel->consider_parallel &&
2954  subpath->parallel_safe;
2955  pathnode->path.parallel_workers = subpath->parallel_workers;
2956  pathnode->path.pathkeys = pathkeys;
2957 
2958  pathnode->subpath = subpath;
2959 
2960  cost_incremental_sort(&pathnode->path,
2961  root, pathkeys, presorted_keys,
2962  subpath->startup_cost,
2963  subpath->total_cost,
2964  subpath->rows,
2965  subpath->pathtarget->width,
2966  0.0, /* XXX comparison_cost shouldn't be 0? */
2967  work_mem, limit_tuples);
2968 
2969  sort->nPresortedCols = presorted_keys;
2970 
2971  return sort;
2972 }
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:1987
Path path
Definition: pathnodes.h:2179
Path * subpath
Definition: pathnodes.h:2180

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

Referenced by create_final_distinct_paths(), create_one_window_path(), create_ordered_paths(), create_partial_distinct_paths(), gather_grouping_paths(), generate_useful_gather_paths(), and make_ordered_path().

◆ 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 995 of file pathnode.c.

1006 {
1007  IndexPath *pathnode = makeNode(IndexPath);
1008  RelOptInfo *rel = index->rel;
1009 
1010  pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
1011  pathnode->path.parent = rel;
1012  pathnode->path.pathtarget = rel->reltarget;
1013  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1014  required_outer);
1015  pathnode->path.parallel_aware = false;
1016  pathnode->path.parallel_safe = rel->consider_parallel;
1017  pathnode->path.parallel_workers = 0;
1018  pathnode->path.pathkeys = pathkeys;
1019 
1020  pathnode->indexinfo = index;
1021  pathnode->indexclauses = indexclauses;
1022  pathnode->indexorderbys = indexorderbys;
1023  pathnode->indexorderbycols = indexorderbycols;
1024  pathnode->indexscandir = indexscandir;
1025 
1026  cost_index(pathnode, root, loop_count, partial_path);
1027 
1028  return pathnode;
1029 }
void cost_index(IndexPath *path, PlannerInfo *root, double loop_count, bool partial_path)
Definition: costsize.c:550
List * indexclauses
Definition: pathnodes.h:1691
ScanDirection indexscandir
Definition: pathnodes.h:1694
Path path
Definition: pathnodes.h:1689
List * indexorderbycols
Definition: pathnodes.h:1693
List * indexorderbys
Definition: pathnodes.h:1692
IndexOptInfo * indexinfo
Definition: pathnodes.h:1690
Definition: type.h:95

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, IndexPath::path, Path::pathkeys, Path::pathtype, and RelOptInfo::reltarget.

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 3805 of file pathnode.c.

3810 {
3811  LimitPath *pathnode = makeNode(LimitPath);
3812 
3813  pathnode->path.pathtype = T_Limit;
3814  pathnode->path.parent = rel;
3815  /* Limit doesn't project, so use source path's pathtarget */
3816  pathnode->path.pathtarget = subpath->pathtarget;
3817  /* For now, assume we are above any joins, so no parameterization */
3818  pathnode->path.param_info = NULL;
3819  pathnode->path.parallel_aware = false;
3820  pathnode->path.parallel_safe = rel->consider_parallel &&
3821  subpath->parallel_safe;
3822  pathnode->path.parallel_workers = subpath->parallel_workers;
3823  pathnode->path.rows = subpath->rows;
3824  pathnode->path.startup_cost = subpath->startup_cost;
3825  pathnode->path.total_cost = subpath->total_cost;
3826  pathnode->path.pathkeys = subpath->pathkeys;
3827  pathnode->subpath = subpath;
3828  pathnode->limitOffset = limitOffset;
3829  pathnode->limitCount = limitCount;
3830  pathnode->limitOption = limitOption;
3831 
3832  /*
3833  * Adjust the output rows count and costs according to the offset/limit.
3834  */
3835  adjust_limit_rows_costs(&pathnode->path.rows,
3836  &pathnode->path.startup_cost,
3837  &pathnode->path.total_cost,
3838  offset_est, count_est);
3839 
3840  return pathnode;
3841 }
void adjust_limit_rows_costs(double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
Definition: pathnode.c:3860
Path path
Definition: pathnodes.h:2377
Path * subpath
Definition: pathnodes.h:2378
LimitOption limitOption
Definition: pathnodes.h:2381
Node * limitOffset
Definition: pathnodes.h:2379
Node * limitCount
Definition: pathnodes.h:2380

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

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

◆ create_lockrows_path()

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

Definition at line 3644 of file pathnode.c.

3646 {
3647  LockRowsPath *pathnode = makeNode(LockRowsPath);
3648 
3649  pathnode->path.pathtype = T_LockRows;
3650  pathnode->path.parent = rel;
3651  /* LockRows doesn't project, so use source path's pathtarget */
3652  pathnode->path.pathtarget = subpath->pathtarget;
3653  /* For now, assume we are above any joins, so no parameterization */
3654  pathnode->path.param_info = NULL;
3655  pathnode->path.parallel_aware = false;
3656  pathnode->path.parallel_safe = false;
3657  pathnode->path.parallel_workers = 0;
3658  pathnode->path.rows = subpath->rows;
3659 
3660  /*
3661  * The result cannot be assumed sorted, since locking might cause the sort
3662  * key columns to be replaced with new values.
3663  */
3664  pathnode->path.pathkeys = NIL;
3665 
3666  pathnode->subpath = subpath;
3667  pathnode->rowMarks = rowMarks;
3668  pathnode->epqParam = epqParam;
3669 
3670  /*
3671  * We should charge something extra for the costs of row locking and
3672  * possible refetches, but it's hard to say how much. For now, use
3673  * cpu_tuple_cost per row.
3674  */
3675  pathnode->path.startup_cost = subpath->startup_cost;
3676  pathnode->path.total_cost = subpath->total_cost +
3677  cpu_tuple_cost * subpath->rows;
3678 
3679  return pathnode;
3680 }
Path * subpath
Definition: pathnodes.h:2340
List * rowMarks
Definition: pathnodes.h:2341

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

Referenced by grouping_planner().

◆ create_material_path()

MaterialPath* create_material_path ( RelOptInfo rel,
Path subpath 
)

Definition at line 1568 of file pathnode.c.

1569 {
1570  MaterialPath *pathnode = makeNode(MaterialPath);
1571 
1572  Assert(subpath->parent == rel);
1573 
1574  pathnode->path.pathtype = T_Material;
1575  pathnode->path.parent = rel;
1576  pathnode->path.pathtarget = rel->reltarget;
1577  pathnode->path.param_info = subpath->param_info;
1578  pathnode->path.parallel_aware = false;
1579  pathnode->path.parallel_safe = rel->consider_parallel &&
1580  subpath->parallel_safe;
1581  pathnode->path.parallel_workers = subpath->parallel_workers;
1582  pathnode->path.pathkeys = subpath->pathkeys;
1583 
1584  pathnode->subpath = subpath;
1585 
1586  cost_material(&pathnode->path,
1587  subpath->startup_cost,
1588  subpath->total_cost,
1589  subpath->rows,
1590  subpath->pathtarget->width);
1591 
1592  return pathnode;
1593 }
void cost_material(Path *path, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition: costsize.c:2454
Path * subpath
Definition: pathnodes.h:1962

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

Referenced by match_unsorted_outer(), reparameterize_path(), 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 1600 of file pathnode.c.

1603 {
1604  MemoizePath *pathnode = makeNode(MemoizePath);
1605 
1606  Assert(subpath->parent == rel);
1607 
1608  pathnode->path.pathtype = T_Memoize;
1609  pathnode->path.parent = rel;
1610  pathnode->path.pathtarget = rel->reltarget;
1611  pathnode->path.param_info = subpath->param_info;
1612  pathnode->path.parallel_aware = false;
1613  pathnode->path.parallel_safe = rel->consider_parallel &&
1614  subpath->parallel_safe;
1615  pathnode->path.parallel_workers = subpath->parallel_workers;
1616  pathnode->path.pathkeys = subpath->pathkeys;
1617 
1618  pathnode->subpath = subpath;
1619  pathnode->hash_operators = hash_operators;
1620  pathnode->param_exprs = param_exprs;
1621  pathnode->singlerow = singlerow;
1622  pathnode->binary_mode = binary_mode;
1623  pathnode->calls = calls;
1624 
1625  /*
1626  * For now we set est_entries to 0. cost_memoize_rescan() does all the
1627  * hard work to determine how many cache entries there are likely to be,
1628  * so it seems best to leave it up to that function to fill this field in.
1629  * If left at 0, the executor will make a guess at a good value.
1630  */
1631  pathnode->est_entries = 0;
1632 
1633  /*
1634  * Add a small additional charge for caching the first entry. All the
1635  * harder calculations for rescans are performed in cost_memoize_rescan().
1636  */
1637  pathnode->path.startup_cost = subpath->startup_cost + cpu_tuple_cost;
1638  pathnode->path.total_cost = subpath->total_cost + cpu_tuple_cost;
1639  pathnode->path.rows = subpath->rows;
1640 
1641  return pathnode;
1642 }
bool singlerow
Definition: pathnodes.h:1976
List * hash_operators
Definition: pathnodes.h:1974
uint32 est_entries
Definition: pathnodes.h:1981
bool binary_mode
Definition: pathnodes.h:1978
Cardinality calls
Definition: pathnodes.h:1980
Path * subpath
Definition: pathnodes.h:1973
List * param_exprs
Definition: pathnodes.h:1975

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, MemoizePath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, Path::rows, MemoizePath::singlerow, Path::startup_cost, subpath(), MemoizePath::subpath, 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 1417 of file pathnode.c.

1422 {
1424  Cost input_startup_cost;
1425  Cost input_total_cost;
1426  ListCell *l;
1427 
1428  pathnode->path.pathtype = T_MergeAppend;
1429  pathnode->path.parent = rel;
1430  pathnode->path.pathtarget = rel->reltarget;
1431  pathnode->path.param_info = get_appendrel_parampathinfo(rel,
1432  required_outer);
1433  pathnode->path.parallel_aware = false;
1434  pathnode->path.parallel_safe = rel->consider_parallel;
1435  pathnode->path.parallel_workers = 0;
1436  pathnode->path.pathkeys = pathkeys;
1437  pathnode->subpaths = subpaths;
1438 
1439  /*
1440  * Apply query-wide LIMIT if known and path is for sole base relation.
1441  * (Handling this at this low level is a bit klugy.)
1442  */
1443  if (bms_equal(rel->relids, root->all_query_rels))
1444  pathnode->limit_tuples = root->limit_tuples;
1445  else
1446  pathnode->limit_tuples = -1.0;
1447 
1448  /*
1449  * Add up the sizes and costs of the input paths.
1450  */
1451  pathnode->path.rows = 0;
1452  input_startup_cost = 0;
1453  input_total_cost = 0;
1454  foreach(l, subpaths)
1455  {
1456  Path *subpath = (Path *) lfirst(l);
1457 
1458  pathnode->path.rows += subpath->rows;
1459  pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1460  subpath->parallel_safe;
1461 
1462  if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
1463  {
1464  /* Subpath is adequately ordered, we won't need to sort it */
1465  input_startup_cost += subpath->startup_cost;
1466  input_total_cost += subpath->total_cost;
1467  }
1468  else
1469  {
1470  /* We'll need to insert a Sort node, so include cost for that */
1471  Path sort_path; /* dummy for result of cost_sort */
1472 
1473  cost_sort(&sort_path,
1474  root,
1475  pathkeys,
1476  subpath->total_cost,
1477  subpath->rows,
1478  subpath->pathtarget->width,
1479  0.0,
1480  work_mem,
1481  pathnode->limit_tuples);
1482  input_startup_cost += sort_path.startup_cost;
1483  input_total_cost += sort_path.total_cost;
1484  }
1485 
1486  /* All child paths must have same parameterization */
1487  Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
1488  }
1489 
1490  /*
1491  * Now we can compute total costs of the MergeAppend. If there's exactly
1492  * one child path and its parallel awareness matches that of the
1493  * MergeAppend, then the MergeAppend is a no-op and will be discarded
1494  * later (in setrefs.c); otherwise we do the normal cost calculation.
1495  */
1496  if (list_length(subpaths) == 1 &&
1497  ((Path *) linitial(subpaths))->parallel_aware ==
1498  pathnode->path.parallel_aware)
1499  {
1500  pathnode->path.startup_cost = input_startup_cost;
1501  pathnode->path.total_cost = input_total_cost;
1502  }
1503  else
1504  cost_merge_append(&pathnode->path, root,
1505  pathkeys, list_length(subpaths),
1506  input_startup_cost, input_total_cost,
1507  pathnode->path.rows);
1508 
1509  return pathnode;
1510 }
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:2405
Cardinality limit_tuples
Definition: pathnodes.h:1937

References PlannerInfo::all_query_rels, Assert(), bms_equal(), RelOptInfo::consider_parallel, cost_merge_append(), cost_sort(), get_appendrel_parampathinfo(), lfirst, PlannerInfo::limit_tuples, MergeAppendPath::limit_tuples, linitial, list_length(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, MergeAppendPath::path, PATH_REQ_OUTER, Path::pathkeys, pathkeys_contained_in(), Path::pathtype, RelOptInfo::relids, RelOptInfo::reltarget, Path::rows, Path::startup_cost, subpath(), MergeAppendPath::subpaths, 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 2538 of file pathnode.c.

2551 {
2552  MergePath *pathnode = makeNode(MergePath);
2553 
2554  pathnode->jpath.path.pathtype = T_MergeJoin;
2555  pathnode->jpath.path.parent = joinrel;
2556  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2557  pathnode->jpath.path.param_info =
2559  joinrel,
2560  outer_path,
2561  inner_path,
2562  extra->sjinfo,
2563  required_outer,
2564  &restrict_clauses);
2565  pathnode->jpath.path.parallel_aware = false;
2566  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2567  outer_path->parallel_safe && inner_path->parallel_safe;
2568  /* This is a foolish way to estimate parallel_workers, but for now... */
2569  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2570  pathnode->jpath.path.pathkeys = pathkeys;
2571  pathnode->jpath.jointype = jointype;
2572  pathnode->jpath.inner_unique = extra->inner_unique;
2573  pathnode->jpath.outerjoinpath = outer_path;
2574  pathnode->jpath.innerjoinpath = inner_path;
2575  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2576  pathnode->path_mergeclauses = mergeclauses;
2577  pathnode->outersortkeys = outersortkeys;
2578  pathnode->innersortkeys = innersortkeys;
2579  /* pathnode->skip_mark_restore will be set by final_cost_mergejoin */
2580  /* pathnode->materialize_inner will be set by final_cost_mergejoin */
2581 
2582  final_cost_mergejoin(root, pathnode, workspace, extra);
2583 
2584  return pathnode;
2585 }
void final_cost_mergejoin(PlannerInfo *root, MergePath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:3746
List * outersortkeys
Definition: pathnodes.h:2114
List * innersortkeys
Definition: pathnodes.h:2115
JoinPath jpath
Definition: pathnodes.h:2112
List * path_mergeclauses
Definition: pathnodes.h:2113

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_safe, Path::parallel_workers, MergePath::path_mergeclauses, RelOptInfo::reltarget, and JoinPathExtraData::sjinfo.

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 3382 of file pathnode.c.

3387 {
3388  MinMaxAggPath *pathnode = makeNode(MinMaxAggPath);
3389  Cost initplan_cost;
3390  ListCell *lc;
3391 
3392  /* The topmost generated Plan node will be a Result */
3393  pathnode->path.pathtype = T_Result;
3394  pathnode->path.parent = rel;
3395  pathnode->path.pathtarget = target;
3396  /* For now, assume we are above any joins, so no parameterization */
3397  pathnode->path.param_info = NULL;
3398  pathnode->path.parallel_aware = false;
3399  pathnode->path.parallel_safe = true; /* might change below */
3400  pathnode->path.parallel_workers = 0;
3401  /* Result is one unordered row */
3402  pathnode->path.rows = 1;
3403  pathnode->path.pathkeys = NIL;
3404 
3405  pathnode->mmaggregates = mmaggregates;
3406  pathnode->quals = quals;
3407 
3408  /* Calculate cost of all the initplans, and check parallel safety */
3409  initplan_cost = 0;
3410  foreach(lc, mmaggregates)
3411  {
3412  MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
3413 
3414  initplan_cost += mminfo->pathcost;
3415  if (!mminfo->path->parallel_safe)
3416  pathnode->path.parallel_safe = false;
3417  }
3418 
3419  /* add tlist eval cost for each output row, plus cpu_tuple_cost */
3420  pathnode->path.startup_cost = initplan_cost + target->cost.startup;
3421  pathnode->path.total_cost = initplan_cost + target->cost.startup +
3422  target->cost.per_tuple + cpu_tuple_cost;
3423 
3424  /*
3425  * Add cost of qual, if any --- but we ignore its selectivity, since our
3426  * rowcount estimate should be 1 no matter what the qual is.
3427  */
3428  if (quals)
3429  {
3430  QualCost qual_cost;
3431 
3432  cost_qual_eval(&qual_cost, quals, root);
3433  pathnode->path.startup_cost += qual_cost.startup;
3434  pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
3435  }
3436 
3437  /*
3438  * If the initplans were all parallel-safe, also check safety of the
3439  * target and quals. (The Result node itself isn't parallelizable, but if
3440  * we are in a subquery then it can be useful for the outer query to know
3441  * that this one is parallel-safe.)
3442  */
3443  if (pathnode->path.parallel_safe)
3444  pathnode->path.parallel_safe =
3445  is_parallel_safe(root, (Node *) target->exprs) &&
3446  is_parallel_safe(root, (Node *) quals);
3447 
3448  return pathnode;
3449 }
List * quals
Definition: pathnodes.h:2290
List * mmaggregates
Definition: pathnodes.h:2289

References PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, PathTarget::exprs, is_parallel_safe(), lfirst, makeNode, MinMaxAggPath::mmaggregates, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, MinMaxAggPath::path, MinMaxAggInfo::path, MinMaxAggInfo::pathcost, Path::pathkeys, Path::pathtype, QualCost::per_tuple, MinMaxAggPath::quals, Path::rows, QualCost::startup, Path::startup_cost, 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 3706 of file pathnode.c.

3716 {
3718 
3719  Assert(operation == CMD_MERGE ||
3720  (operation == CMD_UPDATE ?
3721  list_length(resultRelations) == list_length(updateColnosLists) :
3722  updateColnosLists == NIL));
3723  Assert(withCheckOptionLists == NIL ||
3724  list_length(resultRelations) == list_length(withCheckOptionLists));
3725  Assert(returningLists == NIL ||
3726  list_length(resultRelations) == list_length(returningLists));
3727 
3728  pathnode->path.pathtype = T_ModifyTable;
3729  pathnode->path.parent = rel;
3730  /* pathtarget is not interesting, just make it minimally valid */
3731  pathnode->path.pathtarget = rel->reltarget;
3732  /* For now, assume we are above any joins, so no parameterization */
3733  pathnode->path.param_info = NULL;
3734  pathnode->path.parallel_aware = false;
3735  pathnode->path.parallel_safe = false;
3736  pathnode->path.parallel_workers = 0;
3737  pathnode->path.pathkeys = NIL;
3738 
3739  /*
3740  * Compute cost & rowcount as subpath cost & rowcount (if RETURNING)
3741  *
3742  * Currently, we don't charge anything extra for the actual table
3743  * modification work, nor for the WITH CHECK OPTIONS or RETURNING
3744  * expressions if any. It would only be window dressing, since
3745  * ModifyTable is always a top-level node and there is no way for the
3746  * costs to change any higher-level planning choices. But we might want
3747  * to make it look better sometime.
3748  */
3749  pathnode->path.startup_cost = subpath->startup_cost;
3750  pathnode->path.total_cost = subpath->total_cost;
3751  if (returningLists != NIL)
3752  {
3753  pathnode->path.rows = subpath->rows;
3754 
3755  /*
3756  * Set width to match the subpath output. XXX this is totally wrong:
3757  * we should return an average of the RETURNING tlist widths. But
3758  * it's what happened historically, and improving it is a task for
3759  * another day. (Again, it's mostly window dressing.)
3760  */
3761  pathnode->path.pathtarget->width = subpath->pathtarget->width;
3762  }
3763  else
3764  {
3765  pathnode->path.rows = 0;
3766  pathnode->path.pathtarget->width = 0;
3767  }
3768 
3769  pathnode->subpath = subpath;
3770  pathnode->operation = operation;
3771  pathnode->canSetTag = canSetTag;
3772  pathnode->nominalRelation = nominalRelation;
3773  pathnode->rootRelation = rootRelation;
3774  pathnode->partColsUpdated = partColsUpdated;
3775  pathnode->resultRelations = resultRelations;
3776  pathnode->updateColnosLists = updateColnosLists;
3777  pathnode->withCheckOptionLists = withCheckOptionLists;
3778  pathnode->returningLists = returningLists;
3779  pathnode->rowMarks = rowMarks;
3780  pathnode->onconflict = onconflict;
3781  pathnode->epqParam = epqParam;
3782  pathnode->mergeActionLists = mergeActionLists;
3783 
3784  return pathnode;
3785 }
@ CMD_MERGE
Definition: nodes.h:259
@ CMD_UPDATE
Definition: nodes.h:256
bool partColsUpdated
Definition: pathnodes.h:2360
List * returningLists
Definition: pathnodes.h:2364
List * resultRelations
Definition: pathnodes.h:2361
List * withCheckOptionLists
Definition: pathnodes.h:2363
List * updateColnosLists
Definition: pathnodes.h:2362
OnConflictExpr * onconflict
Definition: pathnodes.h:2366
CmdType operation
Definition: pathnodes.h:2356
Index rootRelation
Definition: pathnodes.h:2359
Index nominalRelation
Definition: pathnodes.h:2358
List * mergeActionLists
Definition: pathnodes.h:2368

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, ModifyTablePath::partColsUpdated, ModifyTablePath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, ModifyTablePath::resultRelations, ModifyTablePath::returningLists, ModifyTablePath::rootRelation, ModifyTablePath::rowMarks, Path::rows, Path::startup_cost, subpath(), ModifyTablePath::subpath, Path::total_cost, ModifyTablePath::updateColnosLists, and ModifyTablePath::withCheckOptionLists.

Referenced by grouping_planner().

◆ create_namedtuplestorescan_path()

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

Definition at line 2145 of file pathnode.c.

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

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

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 2452 of file pathnode.c.

2462 {
2463  NestPath *pathnode = makeNode(NestPath);
2464  Relids inner_req_outer = PATH_REQ_OUTER(inner_path);
2465 
2466  /*
2467  * If the inner path is parameterized by the outer, we must drop any
2468  * restrict_clauses that are due to be moved into the inner path. We have
2469  * to do this now, rather than postpone the work till createplan time,
2470  * because the restrict_clauses list can affect the size and cost
2471  * estimates for this path. We detect such clauses by checking for serial
2472  * number match to clauses already enforced in the inner path.
2473  */
2474  if (bms_overlap(inner_req_outer, outer_path->parent->relids))
2475  {
2476  Bitmapset *enforced_serials = get_param_path_clause_serials(inner_path);
2477  List *jclauses = NIL;
2478  ListCell *lc;
2479 
2480  foreach(lc, restrict_clauses)
2481  {
2482  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2483 
2484  if (!bms_is_member(rinfo->rinfo_serial, enforced_serials))
2485  jclauses = lappend(jclauses, rinfo);
2486  }
2487  restrict_clauses = jclauses;
2488  }
2489 
2490  pathnode->jpath.path.pathtype = T_NestLoop;
2491  pathnode->jpath.path.parent = joinrel;
2492  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2493  pathnode->jpath.path.param_info =
2495  joinrel,
2496  outer_path,
2497  inner_path,
2498  extra->sjinfo,
2499  required_outer,
2500  &restrict_clauses);
2501  pathnode->jpath.path.parallel_aware = false;
2502  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2503  outer_path->parallel_safe && inner_path->parallel_safe;
2504  /* This is a foolish way to estimate parallel_workers, but for now... */
2505  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2506  pathnode->jpath.path.pathkeys = pathkeys;
2507  pathnode->jpath.jointype = jointype;
2508  pathnode->jpath.inner_unique = extra->inner_unique;
2509  pathnode->jpath.outerjoinpath = outer_path;
2510  pathnode->jpath.innerjoinpath = inner_path;
2511  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2512 
2513  final_cost_nestloop(root, pathnode, workspace, extra);
2514 
2515  return pathnode;
2516 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:523
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:339
Bitmapset * get_param_path_clause_serials(Path *path)
Definition: relnode.c:1903
JoinPath jpath
Definition: pathnodes.h:2072
int rinfo_serial
Definition: pathnodes.h:2613

References bms_is_member(), bms_overlap(), RelOptInfo::consider_parallel, final_cost_nestloop(), get_joinrel_parampathinfo(), get_param_path_clause_serials(), JoinPath::inner_unique, JoinPathExtraData::inner_unique, JoinPath::innerjoinpath, JoinPath::joinrestrictinfo, JoinPath::jointype, NestPath::jpath, lappend(), lfirst, makeNode, NIL, JoinPath::outerjoinpath, Path::parallel_safe, Path::parallel_workers, PATH_REQ_OUTER, RelOptInfo::reltarget, RestrictInfo::rinfo_serial, and JoinPathExtraData::sjinfo.

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 2670 of file pathnode.c.

2674 {
2675  ProjectionPath *pathnode = makeNode(ProjectionPath);
2676  PathTarget *oldtarget;
2677 
2678  /*
2679  * We mustn't put a ProjectionPath directly above another; it's useless
2680  * and will confuse create_projection_plan. Rather than making sure all
2681  * callers handle that, let's implement it here, by stripping off any
2682  * ProjectionPath in what we're given. Given this rule, there won't be
2683  * more than one.
2684  */
2685  if (IsA(subpath, ProjectionPath))
2686  {
2687  ProjectionPath *subpp = (ProjectionPath *) subpath;
2688 
2689  Assert(subpp->path.parent == rel);
2690  subpath = subpp->subpath;
2692  }
2693 
2694  pathnode->path.pathtype = T_Result;
2695  pathnode->path.parent = rel;
2696  pathnode->path.pathtarget = target;
2697  /* For now, assume we are above any joins, so no parameterization */
2698  pathnode->path.param_info = NULL;
2699  pathnode->path.parallel_aware = false;
2700  pathnode->path.parallel_safe = rel->consider_parallel &&
2701  subpath->parallel_safe &&
2702  is_parallel_safe(root, (Node *) target->exprs);
2703  pathnode->path.parallel_workers = subpath->parallel_workers;
2704  /* Projection does not change the sort order */
2705  pathnode->path.pathkeys = subpath->pathkeys;
2706 
2707  pathnode->subpath = subpath;
2708 
2709  /*
2710  * We might not need a separate Result node. If the input plan node type
2711  * can project, we can just tell it to project something else. Or, if it
2712  * can't project but the desired target has the same expression list as
2713  * what the input will produce anyway, we can still give it the desired
2714  * tlist (possibly changing its ressortgroupref labels, but nothing else).
2715  * Note: in the latter case, create_projection_plan has to recheck our
2716  * conclusion; see comments therein.
2717  */
2718  oldtarget = subpath->pathtarget;
2720  equal(oldtarget->exprs, target->exprs))
2721  {
2722  /* No separate Result node needed */
2723  pathnode->dummypp = true;
2724 
2725  /*
2726  * Set cost of plan as subpath's cost, adjusted for tlist replacement.
2727  */
2728  pathnode->path.rows = subpath->rows;
2729  pathnode->path.startup_cost = subpath->startup_cost +
2730  (target->cost.startup - oldtarget->cost.startup);
2731  pathnode->path.total_cost = subpath->total_cost +
2732  (target->cost.startup - oldtarget->cost.startup) +
2733  (target->cost.per_tuple - oldtarget->cost.per_tuple) * subpath->rows;
2734  }
2735  else
2736  {
2737  /* We really do need the Result node */
2738  pathnode->dummypp = false;
2739 
2740  /*
2741  * The Result node's cost is cpu_tuple_cost per row, plus the cost of
2742  * evaluating the tlist. There is no qual to worry about.
2743  */
2744  pathnode->path.rows = subpath->rows;
2745  pathnode->path.startup_cost = subpath->startup_cost +
2746  target->cost.startup;
2747  pathnode->path.total_cost = subpath->total_cost +
2748  target->cost.startup +
2749  (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows;
2750  }
2751 
2752  return pathnode;
2753 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
Path * subpath
Definition: pathnodes.h:2154

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, ProjectionPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, Path::rows, QualCost::startup, Path::startup_cost, subpath(), ProjectionPath::subpath, and Path::total_cost.

Referenced by add_paths_with_pathkeys_for_rel(), 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 3599 of file pathnode.c.

3607 {
3609 
3610  pathnode->path.pathtype = T_RecursiveUnion;
3611  pathnode->path.parent = rel;
3612  pathnode->path.pathtarget = target;
3613  /* For now, assume we are above any joins, so no parameterization */
3614  pathnode->path.param_info = NULL;
3615  pathnode->path.parallel_aware = false;
3616  pathnode->path.parallel_safe = rel->consider_parallel &&
3617  leftpath->parallel_safe && rightpath->parallel_safe;
3618  /* Foolish, but we'll do it like joins for now: */
3619  pathnode->path.parallel_workers = leftpath->parallel_workers;
3620  /* RecursiveUnion result is always unsorted */
3621  pathnode->path.pathkeys = NIL;
3622 
3623  pathnode->leftpath = leftpath;
3624  pathnode->rightpath = rightpath;
3625  pathnode->distinctList = distinctList;
3626  pathnode->wtParam = wtParam;
3627  pathnode->numGroups = numGroups;
3628 
3629  cost_recursive_union(&pathnode->path, leftpath, rightpath);
3630 
3631  return pathnode;
3632 }
void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
Definition: costsize.c:1814
Cardinality numGroups
Definition: pathnodes.h:2331

References RelOptInfo::consider_parallel, cost_recursive_union(), RecursiveUnionPath::distinctList, RecursiveUnionPath::leftpath, makeNode, NIL, RecursiveUnionPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, RecursiveUnionPath::path, Path::pathkeys, Path::pathtype, RecursiveUnionPath::rightpath, 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 2171 of file pathnode.c.

2173 {
2174  Path *pathnode = makeNode(Path);
2175 
2176  pathnode->pathtype = T_Result;
2177  pathnode->parent = rel;
2178  pathnode->pathtarget = rel->reltarget;
2179  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2180  required_outer);
2181  pathnode->parallel_aware = false;
2182  pathnode->parallel_safe = rel->consider_parallel;
2183  pathnode->parallel_workers = 0;
2184  pathnode->pathkeys = NIL; /* result is always unordered */
2185 
2186  cost_resultscan(pathnode, root, rel, pathnode->param_info);
2187 
2188  return pathnode;
2189 }
void cost_resultscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1777

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

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:362

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

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:285

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

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 2867 of file pathnode.c.

2871 {
2872  ProjectSetPath *pathnode = makeNode(ProjectSetPath);
2873  double tlist_rows;
2874  ListCell *lc;
2875 
2876  pathnode->path.pathtype = T_ProjectSet;
2877  pathnode->path.parent = rel;
2878  pathnode->path.pathtarget = target;
2879  /* For now, assume we are above any joins, so no parameterization */
2880  pathnode->path.param_info = NULL;
2881  pathnode->path.parallel_aware = false;
2882  pathnode->path.parallel_safe = rel->consider_parallel &&
2883  subpath->parallel_safe &&
2884  is_parallel_safe(root, (Node *) target->exprs);
2885  pathnode->path.parallel_workers = subpath->parallel_workers;
2886  /* Projection does not change the sort order XXX? */
2887  pathnode->path.pathkeys = subpath->pathkeys;
2888 
2889  pathnode->subpath = subpath;
2890 
2891  /*
2892  * Estimate number of rows produced by SRFs for each row of input; if
2893  * there's more than one in this node, use the maximum.
2894  */
2895  tlist_rows = 1;
2896  foreach(lc, target->exprs)
2897  {
2898  Node *node = (Node *) lfirst(lc);
2899  double itemrows;
2900 
2901  itemrows = expression_returns_set_rows(root, node);
2902  if (tlist_rows < itemrows)
2903  tlist_rows = itemrows;
2904  }
2905 
2906  /*
2907  * In addition to the cost of evaluating the tlist, charge cpu_tuple_cost
2908  * per input row, and half of cpu_tuple_cost for each added output row.
2909  * This is slightly bizarre maybe, but it's what 9.6 did; we may revisit
2910  * this estimate later.
2911  */
2912  pathnode->path.rows = subpath->rows * tlist_rows;
2913  pathnode->path.startup_cost = subpath->startup_cost +
2914  target->cost.startup;
2915  pathnode->path.total_cost = subpath->total_cost +
2916  target->cost.startup +
2917  (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows +
2918  (pathnode->path.rows - subpath->rows) * cpu_tuple_cost / 2;
2919 
2920  return pathnode;
2921 }
double expression_returns_set_rows(PlannerInfo *root, Node *clause)
Definition: clauses.c:291
Path * subpath
Definition: pathnodes.h:2166

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, ProjectSetPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, Path::rows, QualCost::startup, Path::startup_cost, subpath(), ProjectSetPath::subpath, 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 3537 of file pathnode.c.

3547 {
3548  SetOpPath *pathnode = makeNode(SetOpPath);
3549 
3550  pathnode->path.pathtype = T_SetOp;
3551  pathnode->path.parent = rel;
3552  /* SetOp doesn't project, so use source path's pathtarget */
3553  pathnode->path.pathtarget = subpath->pathtarget;
3554  /* For now, assume we are above any joins, so no parameterization */
3555  pathnode->path.param_info = NULL;
3556  pathnode->path.parallel_aware = false;
3557  pathnode->path.parallel_safe = rel->consider_parallel &&
3558  subpath->parallel_safe;
3559  pathnode->path.parallel_workers = subpath->parallel_workers;
3560  /* SetOp preserves the input sort order if in sort mode */
3561  pathnode->path.pathkeys =
3562  (strategy == SETOP_SORTED) ? subpath->pathkeys : NIL;
3563 
3564  pathnode->subpath = subpath;
3565  pathnode->cmd = cmd;
3566  pathnode->strategy = strategy;
3567  pathnode->distinctList = distinctList;
3568  pathnode->flagColIdx = flagColIdx;
3569  pathnode->firstFlag = firstFlag;
3570  pathnode->numGroups = numGroups;
3571 
3572  /*
3573  * Charge one cpu_operator_cost per comparison per input tuple. We assume
3574  * all columns get compared at most of the tuples.
3575  */
3576  pathnode->path.startup_cost = subpath->startup_cost;
3577  pathnode->path.total_cost = subpath->total_cost +
3578  cpu_operator_cost * subpath->rows * list_length(distinctList);
3579  pathnode->path.rows = outputRows;
3580 
3581  return pathnode;
3582 }
double cpu_operator_cost
Definition: costsize.c:124
@ SETOP_SORTED
Definition: nodes.h:395
List * distinctList
Definition: pathnodes.h:2315
Cardinality numGroups
Definition: pathnodes.h:2318
int firstFlag
Definition: pathnodes.h:2317
Path * subpath
Definition: pathnodes.h:2312
SetOpCmd cmd
Definition: pathnodes.h:2313
Path path
Definition: pathnodes.h:2311
SetOpStrategy strategy
Definition: pathnodes.h:2314
AttrNumber flagColIdx
Definition: pathnodes.h:2316

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, SetOpPath::path, Path::pathkeys, Path::pathtype, Path::rows, SETOP_SORTED, Path::startup_cost, SetOpPath::strategy, subpath(), SetOpPath::subpath, 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 2985 of file pathnode.c.

2990 {
2991  SortPath *pathnode = makeNode(SortPath);
2992 
2993  pathnode->path.pathtype = T_Sort;
2994  pathnode->path.parent = rel;
2995  /* Sort doesn't project, so use source path's pathtarget */
2996  pathnode->path.pathtarget = subpath->pathtarget;
2997  /* For now, assume we are above any joins, so no parameterization */
2998  pathnode->path.param_info = NULL;
2999  pathnode->path.parallel_aware = false;
3000  pathnode->path.parallel_safe = rel->consider_parallel &&
3001  subpath->parallel_safe;
3002  pathnode->path.parallel_workers = subpath->parallel_workers;
3003  pathnode->path.pathkeys = pathkeys;
3004 
3005  pathnode->subpath = subpath;
3006 
3007  cost_sort(&pathnode->path, root, pathkeys,
3008  subpath->total_cost,
3009  subpath->rows,
3010  subpath->pathtarget->width,
3011  0.0, /* XXX comparison_cost shouldn't be 0? */
3012  work_mem, limit_tuples);
3013 
3014  return pathnode;
3015 }

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

Referenced by add_paths_with_pathkeys_for_rel(), create_final_distinct_paths(), create_one_window_path(), create_ordered_paths(), create_partial_distinct_paths(), gather_grouping_paths(), generate_nonunion_paths(), generate_useful_gather_paths(), make_ordered_path(), and make_union_unique().

◆ create_subqueryscan_path()

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

Definition at line 2012 of file pathnode.c.

2015 {
2017 
2018  pathnode->path.pathtype = T_SubqueryScan;
2019  pathnode->path.parent = rel;
2020  pathnode->path.pathtarget = rel->reltarget;
2021  pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
2022  required_outer);
2023  pathnode->path.parallel_aware = false;
2024  pathnode->path.parallel_safe = rel->consider_parallel &&
2025  subpath->parallel_safe;
2026  pathnode->path.parallel_workers = subpath->parallel_workers;
2027  pathnode->path.pathkeys = pathkeys;
2028  pathnode->subpath = subpath;
2029 
2030  cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
2031  trivial_pathtarget);
2032 
2033  return pathnode;
2034 }
void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, bool trivial_pathtarget)
Definition: costsize.c:1452

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

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 2068 of file pathnode.c.

2070 {
2071  Path *pathnode = makeNode(Path);
2072 
2073  pathnode->pathtype = T_TableFuncScan;
2074  pathnode->parent = rel;
2075  pathnode->pathtarget = rel->reltarget;
2076  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2077  required_outer);
2078  pathnode->parallel_aware = false;
2079  pathnode->parallel_safe = rel->consider_parallel;
2080  pathnode->parallel_workers = 0;
2081  pathnode->pathkeys = NIL; /* result is always unordered */
2082 
2083  cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
2084 
2085  return pathnode;
2086 }
void cost_tablefuncscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1593

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

Referenced by set_tablefunc_pathlist().

◆ create_tidrangescan_path()

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

Definition at line 1210 of file pathnode.c.

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

References RelOptInfo::consider_parallel, cost_tidrangescan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, TidRangePath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, 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 1181 of file pathnode.c.

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

References RelOptInfo::consider_parallel, cost_tidscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, TidPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, 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 1656 of file pathnode.c.

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

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, UniquePath::path, Path::pathkeys, 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, 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 3088 of file pathnode.c.

3093 {
3095 
3096  pathnode->path.pathtype = T_Unique;
3097  pathnode->path.parent = rel;
3098  /* Unique doesn't project, so use source path's pathtarget */
3099  pathnode->path.pathtarget = subpath->pathtarget;
3100  /* For now, assume we are above any joins, so no parameterization */
3101  pathnode->path.param_info = NULL;
3102  pathnode->path.parallel_aware = false;
3103  pathnode->path.parallel_safe = rel->consider_parallel &&
3104  subpath->parallel_safe;
3105  pathnode->path.parallel_workers = subpath->parallel_workers;
3106  /* Unique doesn't change the input ordering */
3107  pathnode->path.pathkeys = subpath->pathkeys;
3108 
3109  pathnode->subpath = subpath;
3110  pathnode->numkeys = numCols;
3111 
3112  /*
3113  * Charge one cpu_operator_cost per comparison per input tuple. We assume
3114  * all columns get compared at most of the tuples. (XXX probably this is
3115  * an overestimate.)
3116  */
3117  pathnode->path.startup_cost = subpath->startup_cost;
3118  pathnode->path.total_cost = subpath->total_cost +
3119  cpu_operator_cost * subpath->rows * numCols;
3120  pathnode->path.rows = numGroups;
3121 
3122  return pathnode;
3123 }

References RelOptInfo::consider_parallel, cpu_operator_cost, makeNode, UpperUniquePath::numkeys, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, UpperUniquePath::path, Path::pathkeys, Path::pathtype, Path::rows, Path::startup_cost, subpath(), UpperUniquePath::subpath, 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 2094 of file pathnode.c.

2096 {
2097  Path *pathnode = makeNode(Path);
2098 
2099  pathnode->pathtype = T_ValuesScan;
2100  pathnode->parent = rel;
2101  pathnode->pathtarget = rel->reltarget;
2102  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2103  required_outer);
2104  pathnode->parallel_aware = false;
2105  pathnode->parallel_safe = rel->consider_parallel;
2106  pathnode->parallel_workers = 0;
2107  pathnode->pathkeys = NIL; /* result is always unordered */
2108 
2109  cost_valuesscan(pathnode, root, rel, pathnode->param_info);
2110 
2111  return pathnode;
2112 }
void cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1649

References RelOptInfo::consider_parallel, cost_valuesscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::pathkeys, Path::pathtype, and RelOptInfo::reltarget.

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 3469 of file pathnode.c.

3477 {
3478  WindowAggPath *pathnode = makeNode(WindowAggPath);
3479 
3480  /* qual can only be set for the topwindow */
3481  Assert(qual == NIL || topwindow);
3482 
3483  pathnode->path.pathtype = T_WindowAgg;
3484  pathnode->path.parent = rel;
3485  pathnode->path.pathtarget = target;
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  /* WindowAgg preserves the input sort order */
3493  pathnode->path.pathkeys = subpath->pathkeys;
3494 
3495  pathnode->subpath = subpath;
3496  pathnode->winclause = winclause;
3497  pathnode->qual = qual;
3498  pathnode->topwindow = topwindow;
3499 
3500  /*
3501  * For costing purposes, assume that there are no redundant partitioning
3502  * or ordering columns; it's not worth the trouble to deal with that
3503  * corner case here. So we just pass the unmodified list lengths to
3504  * cost_windowagg.
3505  */
3506  cost_windowagg(&pathnode->path, root,
3507  windowFuncs,
3508  winclause,
3509  subpath->startup_cost,
3510  subpath->total_cost,
3511  subpath->rows);
3512 
3513  /* add tlist eval cost for each output row */
3514  pathnode->path.startup_cost += target->cost.startup;
3515  pathnode->path.total_cost += target->cost.startup +
3516  target->cost.per_tuple * pathnode->path.rows;
3517 
3518  return pathnode;
3519 }
void cost_windowagg(Path *path, PlannerInfo *root, List *windowFuncs, WindowClause *winclause, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition: costsize.c:3069
Path * subpath
Definition: pathnodes.h:2299
WindowClause * winclause
Definition: pathnodes.h:2300

References Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cost_windowagg(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, WindowAggPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, WindowAggPath::qual, Path::rows, QualCost::startup, Path::startup_cost, subpath(), WindowAggPath::subpath, 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 2197 of file pathnode.c.

2199 {
2200  Path *pathnode = makeNode(Path);
2201 
2202  pathnode->pathtype = T_WorkTableScan;
2203  pathnode->parent = rel;
2204  pathnode->pathtarget = rel->reltarget;
2205  pathnode->param_info = get_baserel_parampathinfo(root, rel,
2206  required_outer);
2207  pathnode->parallel_aware = false;
2208  pathnode->parallel_safe = rel->consider_parallel;
2209  pathnode->parallel_workers = 0;
2210  pathnode->pathkeys = NIL; /* result is always unordered */
2211 
2212  /* Cost is the same as for a regular CTE scan */
2213  cost_ctescan(pathnode, root, rel, pathnode->param_info);
2214 
2215  return pathnode;
2216 }

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

Referenced by set_worktable_pathlist().

◆ reparameterize_path()

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

Definition at line 3928 of file pathnode.c.

3931 {
3932  RelOptInfo *rel = path->parent;
3933 
3934  /* Can only increase, not decrease, path's parameterization */
3935  if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
3936  return NULL;
3937  switch (path->pathtype)
3938  {
3939  case T_SeqScan:
3940  return create_seqscan_path(root, rel, required_outer, 0);
3941  case T_SampleScan:
3942  return (Path *) create_samplescan_path(root, rel, required_outer);
3943  case T_IndexScan:
3944  case T_IndexOnlyScan:
3945  {
3946  IndexPath *ipath = (IndexPath *) path;
3947  IndexPath *newpath = makeNode(IndexPath);
3948 
3949  /*
3950  * We can't use create_index_path directly, and would not want
3951  * to because it would re-compute the indexqual conditions
3952  * which is wasted effort. Instead we hack things a bit:
3953  * flat-copy the path node, revise its param_info, and redo
3954  * the cost estimate.
3955  */
3956  memcpy(newpath, ipath, sizeof(IndexPath));
3957  newpath->path.param_info =
3958  get_baserel_parampathinfo(root, rel, required_outer);
3959  cost_index(newpath, root, loop_count, false);
3960  return (Path *) newpath;
3961  }
3962  case T_BitmapHeapScan:
3963  {
3964  BitmapHeapPath *bpath = (BitmapHeapPath *) path;
3965 
3966  return (Path *) create_bitmap_heap_path(root,
3967  rel,
3968  bpath->bitmapqual,
3969  required_outer,
3970  loop_count, 0);
3971  }
3972  case T_SubqueryScan:
3973  {
3974  SubqueryScanPath *spath = (SubqueryScanPath *) path;
3975  Path *subpath = spath->subpath;
3976  bool trivial_pathtarget;
3977 
3978  /*
3979  * If existing node has zero extra cost, we must have decided
3980  * its target is trivial. (The converse is not true, because
3981  * it might have a trivial target but quals to enforce; but in
3982  * that case the new node will too, so it doesn't matter
3983  * whether we get the right answer here.)
3984  */
3985  trivial_pathtarget =
3986  (subpath->total_cost == spath->path.total_cost);
3987 
3988  return (Path *) create_subqueryscan_path(root,
3989  rel,
3990  subpath,
3991  trivial_pathtarget,
3992  spath->path.pathkeys,
3993  required_outer);
3994  }
3995  case T_Result:
3996  /* Supported only for RTE_RESULT scan paths */
3997  if (IsA(path, Path))
3998  return create_resultscan_path(root, rel, required_outer);
3999  break;
4000  case T_Append:
4001  {
4002  AppendPath *apath = (AppendPath *) path;
4003  List *childpaths = NIL;
4004  List *partialpaths = NIL;
4005  int i;
4006  ListCell *lc;
4007 
4008  /* Reparameterize the children */
4009  i = 0;
4010  foreach(lc, apath->subpaths)
4011  {
4012  Path *spath = (Path *) lfirst(lc);
4013 
4014  spath = reparameterize_path(root, spath,
4015  required_outer,
4016  loop_count);
4017  if (spath == NULL)
4018  return NULL;
4019  /* We have to re-split the regular and partial paths */
4020  if (i < apath->first_partial_path)
4021  childpaths = lappend(childpaths, spath);
4022  else
4023  partialpaths = lappend(partialpaths, spath);
4024  i++;
4025  }
4026  return (Path *)
4027  create_append_path(root, rel, childpaths, partialpaths,
4028  apath->path.pathkeys, required_outer,
4029  apath->path.parallel_workers,
4030  apath->path.parallel_aware,
4031  -1);
4032  }
4033  case T_Material:
4034  {
4035  MaterialPath *mpath = (MaterialPath *) path;
4036  Path *spath = mpath->subpath;
4037 
4038  spath = reparameterize_path(root, spath,
4039  required_outer,
4040  loop_count);
4041  if (spath == NULL)
4042  return NULL;
4043  return (Path *) create_material_path(rel, spath);
4044  }
4045  case T_Memoize:
4046  {
4047  MemoizePath *mpath = (MemoizePath *) path;
4048  Path *spath = mpath->subpath;
4049 
4050  spath = reparameterize_path(root, spath,
4051  required_outer,
4052  loop_count);
4053  if (spath == NULL)
4054  return NULL;
4055  return (Path *) create_memoize_path(root, rel,
4056  spath,
4057  mpath->param_exprs,
4058  mpath->hash_operators,
4059  mpath->singlerow,
4060  mpath->binary_mode,
4061  mpath->calls);
4062  }
4063  default:
4064  break;
4065  }
4066  return NULL;
4067 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:425
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:1246
Path * create_resultscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Definition: pathnode.c:2171
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:1600
Path * reparameterize_path(PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
Definition: pathnode.c:3928
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
Definition: pathnode.c:2012
MaterialPath * create_material_path(RelOptInfo *rel, Path *subpath)
Definition: pathnode.c:1568
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:1044

References MemoizePath::binary_mode, BitmapHeapPath::bitmapqual, bms_is_subset(), MemoizePath::calls, cost_index(), create_append_path(), create_bitmap_heap_path(), create_material_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, IndexPath::path, SubqueryScanPath::path, AppendPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, MemoizePath::singlerow, subpath(), SubqueryScanPath::subpath, MaterialPath::subpath, MemoizePath::subpath, AppendPath::subpaths, and Path::total_cost.

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 4089 of file pathnode.c.

4091 {
4092 
4093 #define FLAT_COPY_PATH(newnode, node, nodetype) \
4094  ( (newnode) = makeNode(nodetype), \
4095  memcpy((newnode), (node), sizeof(nodetype)) )
4096 
4097 #define ADJUST_CHILD_ATTRS(node) \
4098  ((node) = \
4099  (List *) adjust_appendrel_attrs_multilevel(root, (Node *) (node), \
4100  child_rel, \
4101  child_rel->top_parent))
4102 
4103 #define REPARAMETERIZE_CHILD_PATH(path) \
4104 do { \
4105  (path) = reparameterize_path_by_child(root, (path), child_rel); \
4106  if ((path) == NULL) \
4107  return NULL; \
4108 } while(0)
4109 
4110 #define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
4111 do { \
4112  if ((pathlist) != NIL) \
4113  { \
4114  (pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
4115  child_rel); \
4116  if ((pathlist) == NIL) \
4117  return NULL; \
4118  } \
4119 } while(0)
4120 
4121  Path *new_path;
4122  ParamPathInfo *new_ppi;
4123  ParamPathInfo *old_ppi;
4124  Relids required_outer;
4125 
4126  /*
4127  * If the path is not parameterized by parent of the given relation, it
4128  * doesn't need reparameterization.
4129  */
4130  if (!path->param_info ||
4131  !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4132  return path;
4133 
4134  /*
4135  * If possible, reparameterize the given path, making a copy.
4136  *
4137  * This function is currently only applied to the inner side of a nestloop
4138  * join that is being partitioned by the partitionwise-join code. Hence,
4139  * we need only support path types that plausibly arise in that context.
4140  * (In particular, supporting sorted path types would be a waste of code
4141  * and cycles: even if we translated them here, they'd just lose in
4142  * subsequent cost comparisons.) If we do see an unsupported path type,
4143  * that just means we won't be able to generate a partitionwise-join plan
4144  * using that path type.
4145  */
4146  switch (nodeTag(path))
4147  {
4148  case T_Path:
4149  FLAT_COPY_PATH(new_path, path, Path);
4150  break;
4151 
4152  case T_IndexPath:
4153  {
4154  IndexPath *ipath;
4155 
4156  FLAT_COPY_PATH(ipath, path, IndexPath);
4158  new_path = (Path *) ipath;
4159  }
4160  break;
4161 
4162  case T_BitmapHeapPath:
4163  {
4164  BitmapHeapPath *bhpath;
4165 
4166  FLAT_COPY_PATH(bhpath, path, BitmapHeapPath);
4168  new_path = (Path *) bhpath;
4169  }
4170  break;
4171 
4172  case T_BitmapAndPath:
4173  {
4174  BitmapAndPath *bapath;
4175 
4176  FLAT_COPY_PATH(bapath, path, BitmapAndPath);
4178  new_path = (Path *) bapath;
4179  }
4180  break;
4181 
4182  case T_BitmapOrPath:
4183  {
4184  BitmapOrPath *bopath;
4185 
4186  FLAT_COPY_PATH(bopath, path, BitmapOrPath);
4188  new_path = (Path *) bopath;
4189  }
4190  break;
4191 
4192  case T_ForeignPath:
4193  {
4194  ForeignPath *fpath;
4196 
4197  FLAT_COPY_PATH(fpath, path, ForeignPath);
4198  if (fpath->fdw_outerpath)
4200  if (fpath->fdw_restrictinfo)
4202 
4203  /* Hand over to FDW if needed. */
4204  rfpc_func =
4205  path->parent->fdwroutine->ReparameterizeForeignPathByChild;
4206  if (rfpc_func)
4207  fpath->fdw_private = rfpc_func(root, fpath->fdw_private,
4208  child_rel);
4209  new_path = (Path *) fpath;
4210  }
4211  break;
4212 
4213  case T_CustomPath:
4214  {
4215  CustomPath *cpath;
4216 
4217  FLAT_COPY_PATH(cpath, path, CustomPath);
4219  if (cpath->custom_restrictinfo)
4221  if (cpath->methods &&
4223  cpath->custom_private =
4225  cpath->custom_private,
4226  child_rel);
4227  new_path = (Path *) cpath;
4228  }
4229  break;
4230 
4231  case T_NestPath:
4232  {
4233  JoinPath *jpath;
4234  NestPath *npath;
4235 
4236  FLAT_COPY_PATH(npath, path, NestPath);
4237 
4238  jpath = (JoinPath *) npath;
4242  new_path = (Path *) npath;
4243  }
4244  break;
4245 
4246  case T_MergePath:
4247  {
4248  JoinPath *jpath;
4249  MergePath *mpath;
4250 
4251  FLAT_COPY_PATH(mpath, path, MergePath);
4252 
4253  jpath = (JoinPath *) mpath;
4258  new_path = (Path *) mpath;
4259  }
4260  break;
4261 
4262  case T_HashPath:
4263  {
4264  JoinPath *jpath;
4265  HashPath *hpath;
4266 
4267  FLAT_COPY_PATH(hpath, path, HashPath);
4268 
4269  jpath = (JoinPath *) hpath;
4274  new_path = (Path *) hpath;
4275  }
4276  break;
4277 
4278  case T_AppendPath:
4279  {
4280  AppendPath *apath;
4281 
4282  FLAT_COPY_PATH(apath, path, AppendPath);
4284  new_path = (Path *) apath;
4285  }
4286  break;
4287 
4288  case T_MaterialPath:
4289  {
4290  MaterialPath *mpath;
4291 
4292  FLAT_COPY_PATH(mpath, path, MaterialPath);
4294  new_path = (Path *) mpath;
4295  }
4296  break;
4297 
4298  case T_MemoizePath:
4299  {
4300  MemoizePath *mpath;
4301 
4302  FLAT_COPY_PATH(mpath, path, MemoizePath);
4305  new_path = (Path *) mpath;
4306  }
4307  break;
4308 
4309  case T_GatherPath:
4310  {
4311  GatherPath *gpath;
4312 
4313  FLAT_COPY_PATH(gpath, path, GatherPath);
4315  new_path = (Path *) gpath;
4316  }
4317  break;
4318 
4319  default:
4320 
4321  /* We don't know how to reparameterize this path. */
4322  return NULL;
4323  }
4324 
4325  /*
4326  * Adjust the parameterization information, which refers to the topmost
4327  * parent. The topmost parent can be multiple levels away from the given
4328  * child, hence use multi-level expression adjustment routines.
4329  */
4330  old_ppi = new_path->param_info;
4331  required_outer =
4333  child_rel,
4334  child_rel->top_parent);
4335 
4336  /* If we already have a PPI for this parameterization, just return it */
4337  new_ppi = find_param_path_info(new_path->parent, required_outer);
4338 
4339  /*
4340  * If not, build a new one and link it to the list of PPIs. For the same
4341  * reason as explained in mark_dummy_rel(), allocate new PPI in the same
4342  * context the given RelOptInfo is in.
4343  */
4344  if (new_ppi == NULL)
4345  {
4346  MemoryContext oldcontext;
4347  RelOptInfo *rel = path->parent;
4348 
4349  oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel));
4350 
4351  new_ppi = makeNode(ParamPathInfo);
4352  new_ppi->ppi_req_outer = bms_copy(required_outer);
4353  new_ppi->ppi_rows = old_ppi->ppi_rows;
4354  new_ppi->ppi_clauses = old_ppi->ppi_clauses;
4355  ADJUST_CHILD_ATTRS(new_ppi->ppi_clauses);
4356  new_ppi->ppi_serials = bms_copy(old_ppi->ppi_serials);
4357  rel->ppilist = lappend(rel->ppilist, new_ppi);
4358 
4359  MemoryContextSwitchTo(oldcontext);
4360  }
4361  bms_free(required_outer);
4362 
4363  new_path->param_info = new_ppi;
4364 
4365  /*
4366  * Adjust the path target if the parent of the outer relation is
4367  * referenced in the targetlist. This can happen when only the parent of
4368  * outer relation is laterally referenced in this relation.
4369  */
4370  if (bms_overlap(path->parent->lateral_relids,
4371  child_rel->top_parent_relids))
4372  {
4373  new_path->pathtarget = copy_pathtarget(new_path->pathtarget);
4374  ADJUST_CHILD_ATTRS(new_path->pathtarget->exprs);
4375  }
4376 
4377  return new_path;
4378 }
Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition: appendinfo.c:588
void bms_free(Bitmapset *a)
Definition: bitmapset.c:252
List *(* ReparameterizeForeignPathByChild_function)(PlannerInfo *root, List *fdw_private, RelOptInfo *child_rel)
Definition: fdwapi.h:182
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist)
#define REPARAMETERIZE_CHILD_PATH(path)
#define FLAT_COPY_PATH(newnode, node, nodetype)
#define ADJUST_CHILD_ATTRS(node)
ParamPathInfo * find_param_path_info(RelOptInfo *rel, Relids required_outer)
Definition: relnode.c:1882
struct List *(* ReparameterizeCustomPathByChild)(PlannerInfo *root, List *custom_private, RelOptInfo *child_rel)
Definition: extensible.h:103
const struct CustomPathMethods * methods
Definition: pathnodes.h:1891
List * custom_paths
Definition: pathnodes.h:1888
List * custom_private
Definition: pathnodes.h:1890
List * custom_restrictinfo
Definition: pathnodes.h:1889
Cardinality ppi_rows
Definition: pathnodes.h:1560
List * ppi_clauses
Definition: pathnodes.h:1561
Bitmapset * ppi_serials
Definition: pathnodes.h:1562
Relids ppi_req_outer
Definition: pathnodes.h:1559
List * ppilist
Definition: pathnodes.h:884
Relids top_parent_relids
Definition: pathnodes.h:990
PathTarget * copy_pathtarget(PathTarget *src)
Definition: tlist.c:657

References ADJUST_CHILD_ATTRS, adjust_child_relids_multilevel(), BitmapHeapPath::bitmapqual, BitmapAndPath::bitmapquals, BitmapOrPath::bitmapquals, bms_copy(), bms_free(), bms_overlap(), copy_pathtarget(), CustomPath::custom_paths, CustomPath::custom_private, CustomPath::custom_restrictinfo, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, ForeignPath::fdw_restrictinfo, find_param_path_info(), FLAT_COPY_PATH, GetMemoryChunkContext(), IndexPath::indexclauses, JoinPath::innerjoinpath, JoinPath::joinrestrictinfo, lappend(), makeNode, MemoryContextSwitchTo(), CustomPath::methods, nodeTag, JoinPath::outerjoinpath, MemoizePath::param_exprs, HashPath::path_hashclauses, MergePath::path_mergeclauses, PATH_REQ_OUTER, ParamPathInfo::ppi_clauses, ParamPathInfo::ppi_req_outer, ParamPathInfo::ppi_rows, ParamPathInfo::ppi_serials, RelOptInfo::ppilist, REPARAMETERIZE_CHILD_PATH, REPARAMETERIZE_CHILD_PATH_LIST, CustomPathMethods::ReparameterizeCustomPathByChild, MaterialPath::subpath, MemoizePath::subpath, GatherPath::subpath, AppendPath::subpaths, and RelOptInfo::top_parent_relids.

Referenced by reparameterize_pathlist_by_child(), try_nestloop_path(), and try_partial_nestloop_path().

◆ reparameterize_pathlist_by_child()

static List * reparameterize_pathlist_by_child ( PlannerInfo root,
List pathlist,
RelOptInfo child_rel 
)
static

Definition at line 4385 of file pathnode.c.

4388 {
4389  ListCell *lc;
4390  List *result = NIL;
4391 
4392  foreach(lc, pathlist)
4393  {
4394  Path *path = reparameterize_path_by_child(root, lfirst(lc),
4395  child_rel);
4396 
4397  if (path == NULL)
4398  {
4399  list_free(result);
4400  return NIL;
4401  }
4402 
4403  result = lappend(result, path);
4404  }
4405 
4406  return result;
4407 }
void list_free(List *list)
Definition: list.c:1546

References lappend(), lfirst, list_free(), NIL, and reparameterize_path_by_child().

◆ set_cheapest()

void set_cheapest ( RelOptInfo parent_rel)

Definition at line 244 of file pathnode.c.

245 {
246  Path *cheapest_startup_path;
247  Path *cheapest_total_path;
248  Path *best_param_path;
249  List *parameterized_paths;
250  ListCell *p;
251 
252  Assert(IsA(parent_rel, RelOptInfo));
253 
254  if (parent_rel->pathlist == NIL)
255  elog(ERROR, "could not devise a query plan for the given query");
256 
257  cheapest_startup_path = cheapest_total_path = best_param_path = NULL;
258  parameterized_paths = NIL;
259 
260  foreach(p, parent_rel->pathlist)
261  {
262  Path *path = (Path *) lfirst(p);
263  int cmp;
264 
265  if (path->param_info)
266  {
267  /* Parameterized path, so add it to parameterized_paths */
268  parameterized_paths = lappend(parameterized_paths, path);
269 
270  /*
271  * If we have an unparameterized cheapest-total, we no longer care
272  * about finding the best parameterized path, so move on.
273  */
274  if (cheapest_total_path)
275  continue;
276 
277  /*
278  * Otherwise, track the best parameterized path, which is the one
279  * with least total cost among those of the minimum
280  * parameterization.
281  */
282  if (best_param_path == NULL)
283  best_param_path = path;
284  else
285  {
286  switch (bms_subset_compare(PATH_REQ_OUTER(path),
287  PATH_REQ_OUTER(best_param_path)))
288  {
289  case BMS_EQUAL:
290  /* keep the cheaper one */
291  if (compare_path_costs(path, best_param_path,
292  TOTAL_COST) < 0)
293  best_param_path = path;
294  break;
295  case BMS_SUBSET1:
296  /* new path is less-parameterized */
297  best_param_path = path;
298  break;
299  case BMS_SUBSET2:
300  /* old path is less-parameterized, keep it */
301  break;
302  case BMS_DIFFERENT:
303 
304  /*
305  * This means that neither path has the least possible
306  * parameterization for the rel. We'll sit on the old
307  * path until something better comes along.
308  */
309  break;
310  }
311  }