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_private)
 
ForeignPathcreate_foreign_join_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_private)
 
ForeignPathcreate_foreign_upper_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, Cost startup_cost, Cost total_cost, List *pathkeys, Path *fdw_outerpath, List *fdw_private)
 
Relids calc_nestloop_required_outer (Relids outerrelids, Relids outer_paramrels, Relids innerrelids, Relids inner_paramrels)
 
Relids calc_non_nestloop_required_outer (Path *outer_path, Path *inner_path)
 
NestPathcreate_nestloop_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer)
 
MergePathcreate_mergejoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer, List *mergeclauses, List *outersortkeys, List *innersortkeys)
 
HashPathcreate_hashjoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, bool parallel_hash, List *restrict_clauses, Relids required_outer, List *hashclauses)
 
ProjectionPathcreate_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
Pathapply_projection_to_path (PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
 
ProjectSetPathcreate_set_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
IncrementalSortPathcreate_incremental_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
 
SortPathcreate_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
 
GroupPathcreate_group_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *groupClause, List *qual, double numGroups)
 
UpperUniquePathcreate_upper_unique_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
 
AggPathcreate_agg_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, AggStrategy aggstrategy, AggSplit aggsplit, List *groupClause, List *qual, const AggClauseCosts *aggcosts, double numGroups)
 
GroupingSetsPathcreate_groupingsets_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *having_qual, AggStrategy aggstrategy, List *rollups, const AggClauseCosts *agg_costs)
 
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:520
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:176

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

◆ 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:4322
#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:438
void pfree(void *pointer)
Definition: mcxt.c:1436
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
PathKeysComparison compare_pathkeys(List *keys1, List *keys2)
Definition: pathkeys.c:301
#define STD_FUZZ_FACTOR
Definition: pathnode.c:51
PathKeysComparison
Definition: paths.h:195
@ PATHKEYS_BETTER2
Definition: paths.h:198
@ PATHKEYS_BETTER1
Definition: paths.h:197
@ PATHKEYS_DIFFERENT
Definition: paths.h:199
#define lfirst(lc)
Definition: pg_list.h:172
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:390
#define foreach_current_index(cell)
Definition: pg_list.h:403
List * pathkeys
Definition: pathnodes.h:1639
Cost total_cost
Definition: pathnodes.h:1636
bool parallel_safe
Definition: pathnodes.h:1629
bool consider_parallel
Definition: pathnodes.h:878
List * partial_pathlist
Definition: pathnodes.h:891

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:369
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:179
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:1643
Cardinality rows
Definition: pathnodes.h:1634
List * pathlist
Definition: pathnodes.h:889

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:94
@ PATHKEYS_EQUAL
Definition: paths.h:196
Cost startup_cost
Definition: pathnodes.h:1635
bool consider_param_startup
Definition: pathnodes.h:876
bool consider_startup
Definition: pathnodes.h:874

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

3806 {
3807  double input_rows = *rows;
3808  Cost input_startup_cost = *startup_cost;
3809  Cost input_total_cost = *total_cost;
3810 
3811  if (offset_est != 0)
3812  {
3813  double offset_rows;
3814 
3815  if (offset_est > 0)
3816  offset_rows = (double) offset_est;
3817  else
3818  offset_rows = clamp_row_est(input_rows * 0.10);
3819  if (offset_rows > *rows)
3820  offset_rows = *rows;
3821  if (input_rows > 0)
3822  *startup_cost +=
3823  (input_total_cost - input_startup_cost)
3824  * offset_rows / input_rows;
3825  *rows -= offset_rows;
3826  if (*rows < 1)
3827  *rows = 1;
3828  }
3829 
3830  if (count_est != 0)
3831  {
3832  double count_rows;
3833 
3834  if (count_est > 0)
3835  count_rows = (double) count_est;
3836  else
3837  count_rows = clamp_row_est(input_rows * 0.10);
3838  if (count_rows > *rows)
3839  count_rows = *rows;
3840  if (input_rows > 0)
3841  *total_cost = *startup_cost +
3842  (input_total_cost - input_startup_cost)
3843  * count_rows / input_rows;
3844  *rows = count_rows;
3845  if (*rows < 1)
3846  *rows = 1;
3847  }
3848 }
double clamp_row_est(double nrows)
Definition: costsize.c:203
double Cost
Definition: nodes.h:262

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

1396 {
1397  Path *path1 = (Path *) lfirst(a);
1398  Path *path2 = (Path *) lfirst(b);
1399  int cmp;
1400 
1401  cmp = compare_path_costs(path1, path2, STARTUP_COST);
1402  if (cmp != 0)
1403  return -cmp;
1404  return bms_compare(path1->parent->relids, path2->parent->relids);
1405 }
int bms_compare(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:147
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
Definition: pathnode.c:71
@ STARTUP_COST
Definition: pathnodes.h:38
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:747

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

1374 {
1375  Path *path1 = (Path *) lfirst(a);
1376  Path *path2 = (Path *) lfirst(b);
1377  int cmp;
1378 
1379  cmp = compare_path_costs(path1, path2, TOTAL_COST);
1380  if (cmp != 0)
1381  return -cmp;
1382  return bms_compare(path1->parent->relids, path2->parent->relids);
1383 }
@ 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 2746 of file pathnode.c.

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

2364 {
2365  Relids required_outer;
2366 
2367  /* inner_path can require rels from outer path, but not vice versa */
2368  Assert(!bms_overlap(outer_paramrels, innerrelids));
2369  /* easy case if inner path is not parameterized */
2370  if (!inner_paramrels)
2371  return bms_copy(outer_paramrels);
2372  /* else, form the union ... */
2373  required_outer = bms_union(outer_paramrels, inner_paramrels);
2374  /* ... and remove any mention of now-satisfied outer rels */
2375  required_outer = bms_del_members(required_outer,
2376  outerrelids);
2377  return required_outer;
2378 }
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:226
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:960
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:511
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74

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

2388 {
2389  Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
2390  Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
2391  Relids required_outer;
2392 
2393  /* neither path can require rels from the other */
2394  Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids));
2395  Assert(!bms_overlap(inner_paramrels, outer_path->parent->relids));
2396  /* form the union ... */
2397  required_outer = bms_union(outer_paramrels, inner_paramrels);
2398  /* we do not need an explicit test for empty; bms_union gets it right */
2399  return required_outer;
2400 }

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

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

3118 {
3119  AggPath *pathnode = makeNode(AggPath);
3120 
3121  pathnode->path.pathtype = T_Agg;
3122  pathnode->path.parent = rel;
3123  pathnode->path.pathtarget = target;
3124  /* For now, assume we are above any joins, so no parameterization */
3125  pathnode->path.param_info = NULL;
3126  pathnode->path.parallel_aware = false;
3127  pathnode->path.parallel_safe = rel->consider_parallel &&
3128  subpath->parallel_safe;
3129  pathnode->path.parallel_workers = subpath->parallel_workers;
3130  if (aggstrategy == AGG_SORTED)
3131  pathnode->path.pathkeys = subpath->pathkeys; /* preserves order */
3132  else
3133  pathnode->path.pathkeys = NIL; /* output is unordered */
3134  pathnode->subpath = subpath;
3135 
3136  pathnode->aggstrategy = aggstrategy;
3137  pathnode->aggsplit = aggsplit;
3138  pathnode->numGroups = numGroups;
3139  pathnode->transitionSpace = aggcosts ? aggcosts->transitionSpace : 0;
3140  pathnode->groupClause = groupClause;
3141  pathnode->qual = qual;
3142 
3143  cost_agg(&pathnode->path, root,
3144  aggstrategy, aggcosts,
3145  list_length(groupClause), numGroups,
3146  qual,
3147  subpath->startup_cost, subpath->total_cost,
3148  subpath->rows, subpath->pathtarget->width);
3149 
3150  /* add tlist eval cost for each output row */
3151  pathnode->path.startup_cost += target->cost.startup;
3152  pathnode->path.total_cost += target->cost.startup +
3153  target->cost.per_tuple * pathnode->path.rows;
3154 
3155  return pathnode;
3156 }
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:2623
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:241
@ AGG_SORTED
Definition: nodes.h:363
static int list_length(const List *l)
Definition: pg_list.h:152
Size transitionSpace
Definition: pathnodes.h:62
Path * subpath
Definition: pathnodes.h:2215
Cardinality numGroups
Definition: pathnodes.h:2218
AggSplit aggsplit
Definition: pathnodes.h:2217
List * groupClause
Definition: pathnodes.h:2220
uint64 transitionSpace
Definition: pathnodes.h:2219
AggStrategy aggstrategy
Definition: pathnodes.h:2216
Path path
Definition: pathnodes.h:2214
List * qual
Definition: pathnodes.h:2221
NodeTag pathtype
Definition: pathnodes.h:1600
int parallel_workers
Definition: pathnodes.h:1631
bool parallel_aware
Definition: pathnodes.h:1627

References AGG_SORTED, AggPath::aggsplit, AggPath::aggstrategy, RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), AggPath::groupClause, list_length(), makeNode, NIL, AggPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, 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 1242 of file pathnode.c.

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

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:818
void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
Definition: costsize.c:1129
List * bitmapquals
Definition: pathnodes.h:1771

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:985
Path * bitmapqual
Definition: pathnodes.h:1759

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:1173
List * bitmapquals
Definition: pathnodes.h:1784

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

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

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_private 
)

Definition at line 2270 of file pathnode.c.

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

References bms_is_empty, RelOptInfo::consider_parallel, elog(), ERROR, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, 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_private 
)

Definition at line 2320 of file pathnode.c.

2326 {
2327  ForeignPath *pathnode = makeNode(ForeignPath);
2328 
2329  /*
2330  * Upper relations should never have any lateral references, since joining
2331  * is complete.
2332  */
2334 
2335  pathnode->path.pathtype = T_ForeignScan;
2336  pathnode->path.parent = rel;
2337  pathnode->path.pathtarget = target ? target : rel->reltarget;
2338  pathnode->path.param_info = NULL;
2339  pathnode->path.parallel_aware = false;
2340  pathnode->path.parallel_safe = rel->consider_parallel;
2341  pathnode->path.parallel_workers = 0;
2342  pathnode->path.rows = rows;
2343  pathnode->path.startup_cost = startup_cost;
2344  pathnode->path.total_cost = total_cost;
2345  pathnode->path.pathkeys = pathkeys;
2346 
2347  pathnode->fdw_outerpath = fdw_outerpath;
2348  pathnode->fdw_private = fdw_private;
2349 
2350  return pathnode;
2351 }

References Assert(), bms_is_empty, RelOptInfo::consider_parallel, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, 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_private 
)

Definition at line 2226 of file pathnode.c.

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

References Assert(), RelOptInfo::consider_parallel, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, get_baserel_parampathinfo(), IS_SIMPLE_REL, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, 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 2038 of file pathnode.c.

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

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

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

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

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

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

3003 {
3004  GroupPath *pathnode = makeNode(GroupPath);
3005  PathTarget *target = rel->reltarget;
3006 
3007  pathnode->path.pathtype = T_Group;
3008  pathnode->path.parent = rel;
3009  pathnode->path.pathtarget = target;
3010  /* For now, assume we are above any joins, so no parameterization */
3011  pathnode->path.param_info = NULL;
3012  pathnode->path.parallel_aware = false;
3013  pathnode->path.parallel_safe = rel->consider_parallel &&
3014  subpath->parallel_safe;
3015  pathnode->path.parallel_workers = subpath->parallel_workers;
3016  /* Group doesn't change sort ordering */
3017  pathnode->path.pathkeys = subpath->pathkeys;
3018 
3019  pathnode->subpath = subpath;
3020 
3021  pathnode->groupClause = groupClause;
3022  pathnode->qual = qual;
3023 
3024  cost_group(&pathnode->path, root,
3025  list_length(groupClause),
3026  numGroups,
3027  qual,
3028  subpath->startup_cost, subpath->total_cost,
3029  subpath->rows);
3030 
3031  /* add tlist eval cost for each output row */
3032  pathnode->path.startup_cost += target->cost.startup;
3033  pathnode->path.total_cost += target->cost.startup +
3034  target->cost.per_tuple * pathnode->path.rows;
3035 
3036  return pathnode;
3037 }
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:2895
List * qual
Definition: pathnodes.h:2189
List * groupClause
Definition: pathnodes.h:2188
Path * subpath
Definition: pathnodes.h:2187
Path path
Definition: pathnodes.h:2186

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

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

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

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

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

2583 {
2584  HashPath *pathnode = makeNode(HashPath);
2585 
2586  pathnode->jpath.path.pathtype = T_HashJoin;
2587  pathnode->jpath.path.parent = joinrel;
2588  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2589  pathnode->jpath.path.param_info =
2591  joinrel,
2592  outer_path,
2593  inner_path,
2594  extra->sjinfo,
2595  required_outer,
2596  &restrict_clauses);
2597  pathnode->jpath.path.parallel_aware =
2598  joinrel->consider_parallel && parallel_hash;
2599  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2600  outer_path->parallel_safe && inner_path->parallel_safe;
2601  /* This is a foolish way to estimate parallel_workers, but for now... */
2602  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2603 
2604  /*
2605  * A hashjoin never has pathkeys, since its output ordering is
2606  * unpredictable due to possible batching. XXX If the inner relation is
2607  * small enough, we could instruct the executor that it must not batch,
2608  * and then we could assume that the output inherits the outer relation's
2609  * ordering, which might save a sort step. However there is considerable
2610  * downside if our estimate of the inner relation size is badly off. For
2611  * the moment we don't risk it. (Note also that if we wanted to take this
2612  * seriously, joinpath.c would have to consider many more paths for the
2613  * outer rel than it does now.)
2614  */
2615  pathnode->jpath.path.pathkeys = NIL;
2616  pathnode->jpath.jointype = jointype;
2617  pathnode->jpath.inner_unique = extra->inner_unique;
2618  pathnode->jpath.outerjoinpath = outer_path;
2619  pathnode->jpath.innerjoinpath = inner_path;
2620  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2621  pathnode->path_hashclauses = hashclauses;
2622  /* final_cost_hashjoin will fill in pathnode->num_batches */
2623 
2624  final_cost_hashjoin(root, pathnode, workspace, extra);
2625 
2626  return pathnode;
2627 }
void final_cost_hashjoin(PlannerInfo *root, HashPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:3912
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:1600
List * path_hashclauses
Definition: pathnodes.h:2113
JoinPath jpath
Definition: pathnodes.h:2112
SpecialJoinInfo * sjinfo
Definition: pathnodes.h:3167
Path * outerjoinpath
Definition: pathnodes.h:2035
Path * innerjoinpath
Definition: pathnodes.h:2036
JoinType jointype
Definition: pathnodes.h:2030
bool inner_unique
Definition: pathnodes.h:2032
List * joinrestrictinfo
Definition: pathnodes.h:2038

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

2910 {
2912  SortPath *pathnode = &sort->spath;
2913 
2914  pathnode->path.pathtype = T_IncrementalSort;
2915  pathnode->path.parent = rel;
2916  /* Sort doesn't project, so use source path's pathtarget */
2917  pathnode->path.pathtarget = subpath->pathtarget;
2918  /* For now, assume we are above any joins, so no parameterization */
2919  pathnode->path.param_info = NULL;
2920  pathnode->path.parallel_aware = false;
2921  pathnode->path.parallel_safe = rel->consider_parallel &&
2922  subpath->parallel_safe;
2923  pathnode->path.parallel_workers = subpath->parallel_workers;
2924  pathnode->path.pathkeys = pathkeys;
2925 
2926  pathnode->subpath = subpath;
2927 
2928  cost_incremental_sort(&pathnode->path,
2929  root, pathkeys, presorted_keys,
2930  subpath->startup_cost,
2931  subpath->total_cost,
2932  subpath->rows,
2933  subpath->pathtarget->width,
2934  0.0, /* XXX comparison_cost shouldn't be 0? */
2935  work_mem, limit_tuples);
2936 
2937  sort->nPresortedCols = presorted_keys;
2938 
2939  return sort;
2940 }
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:1958
Path path
Definition: pathnodes.h:2160
Path * subpath
Definition: pathnodes.h:2161

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 add_paths_to_grouping_rel(), create_final_distinct_paths(), create_one_window_path(), create_ordered_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), gather_grouping_paths(), and generate_useful_gather_paths().

◆ create_index_path()

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

Definition at line 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:521
List * indexclauses
Definition: pathnodes.h:1685
ScanDirection indexscandir
Definition: pathnodes.h:1688
Path path
Definition: pathnodes.h:1683
List * indexorderbycols
Definition: pathnodes.h:1687
List * indexorderbys
Definition: pathnodes.h:1686
IndexOptInfo * indexinfo
Definition: pathnodes.h:1684
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 3746 of file pathnode.c.

3751 {
3752  LimitPath *pathnode = makeNode(LimitPath);
3753 
3754  pathnode->path.pathtype = T_Limit;
3755  pathnode->path.parent = rel;
3756  /* Limit doesn't project, so use source path's pathtarget */
3757  pathnode->path.pathtarget = subpath->pathtarget;
3758  /* For now, assume we are above any joins, so no parameterization */
3759  pathnode->path.param_info = NULL;
3760  pathnode->path.parallel_aware = false;
3761  pathnode->path.parallel_safe = rel->consider_parallel &&
3762  subpath->parallel_safe;
3763  pathnode->path.parallel_workers = subpath->parallel_workers;
3764  pathnode->path.rows = subpath->rows;
3765  pathnode->path.startup_cost = subpath->startup_cost;
3766  pathnode->path.total_cost = subpath->total_cost;
3767  pathnode->path.pathkeys = subpath->pathkeys;
3768  pathnode->subpath = subpath;
3769  pathnode->limitOffset = limitOffset;
3770  pathnode->limitCount = limitCount;
3771  pathnode->limitOption = limitOption;
3772 
3773  /*
3774  * Adjust the output rows count and costs according to the offset/limit.
3775  */
3776  adjust_limit_rows_costs(&pathnode->path.rows,
3777  &pathnode->path.startup_cost,
3778  &pathnode->path.total_cost,
3779  offset_est, count_est);
3780 
3781  return pathnode;
3782 }
void adjust_limit_rows_costs(double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
Definition: pathnode.c:3801
Path path
Definition: pathnodes.h:2358
Path * subpath
Definition: pathnodes.h:2359
LimitOption limitOption
Definition: pathnodes.h:2362
Node * limitOffset
Definition: pathnodes.h:2360
Node * limitCount
Definition: pathnodes.h:2361

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(), and grouping_planner().

◆ create_lockrows_path()

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

Definition at line 3585 of file pathnode.c.

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

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

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

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

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

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

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

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

2519 {
2520  MergePath *pathnode = makeNode(MergePath);
2521 
2522  pathnode->jpath.path.pathtype = T_MergeJoin;
2523  pathnode->jpath.path.parent = joinrel;
2524  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2525  pathnode->jpath.path.param_info =
2527  joinrel,
2528  outer_path,
2529  inner_path,
2530  extra->sjinfo,
2531  required_outer,
2532  &restrict_clauses);
2533  pathnode->jpath.path.parallel_aware = false;
2534  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2535  outer_path->parallel_safe && inner_path->parallel_safe;
2536  /* This is a foolish way to estimate parallel_workers, but for now... */
2537  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2538  pathnode->jpath.path.pathkeys = pathkeys;
2539  pathnode->jpath.jointype = jointype;
2540  pathnode->jpath.inner_unique = extra->inner_unique;
2541  pathnode->jpath.outerjoinpath = outer_path;
2542  pathnode->jpath.innerjoinpath = inner_path;
2543  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2544  pathnode->path_mergeclauses = mergeclauses;
2545  pathnode->outersortkeys = outersortkeys;
2546  pathnode->innersortkeys = innersortkeys;
2547  /* pathnode->skip_mark_restore will be set by final_cost_mergejoin */
2548  /* pathnode->materialize_inner will be set by final_cost_mergejoin */
2549 
2550  final_cost_mergejoin(root, pathnode, workspace, extra);
2551 
2552  return pathnode;
2553 }
void final_cost_mergejoin(PlannerInfo *root, MergePath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:3476
List * outersortkeys
Definition: pathnodes.h:2095
List * innersortkeys
Definition: pathnodes.h:2096
JoinPath jpath
Definition: pathnodes.h:2093
List * path_mergeclauses
Definition: pathnodes.h:2094

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

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

References PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, lfirst, makeNode, MinMaxAggPath::mmaggregates, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, MinMaxAggPath::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 3647 of file pathnode.c.

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

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

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

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

2430 {
2431  NestPath *pathnode = makeNode(NestPath);
2432  Relids inner_req_outer = PATH_REQ_OUTER(inner_path);
2433 
2434  /*
2435  * If the inner path is parameterized by the outer, we must drop any
2436  * restrict_clauses that are due to be moved into the inner path. We have
2437  * to do this now, rather than postpone the work till createplan time,
2438  * because the restrict_clauses list can affect the size and cost
2439  * estimates for this path. We detect such clauses by checking for serial
2440  * number match to clauses already enforced in the inner path.
2441  */
2442  if (bms_overlap(inner_req_outer, outer_path->parent->relids))
2443  {
2444  Bitmapset *enforced_serials = get_param_path_clause_serials(inner_path);
2445  List *jclauses = NIL;
2446  ListCell *lc;
2447 
2448  foreach(lc, restrict_clauses)
2449  {
2450  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2451 
2452  if (!bms_is_member(rinfo->rinfo_serial, enforced_serials))
2453  jclauses = lappend(jclauses, rinfo);
2454  }
2455  restrict_clauses = jclauses;
2456  }
2457 
2458  pathnode->jpath.path.pathtype = T_NestLoop;
2459  pathnode->jpath.path.parent = joinrel;
2460  pathnode->jpath.path.pathtarget = joinrel->reltarget;
2461  pathnode->jpath.path.param_info =
2463  joinrel,
2464  outer_path,
2465  inner_path,
2466  extra->sjinfo,
2467  required_outer,
2468  &restrict_clauses);
2469  pathnode->jpath.path.parallel_aware = false;
2470  pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2471  outer_path->parallel_safe && inner_path->parallel_safe;
2472  /* This is a foolish way to estimate parallel_workers, but for now... */
2473  pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2474  pathnode->jpath.path.pathkeys = pathkeys;
2475  pathnode->jpath.jointype = jointype;
2476  pathnode->jpath.inner_unique = extra->inner_unique;
2477  pathnode->jpath.outerjoinpath = outer_path;
2478  pathnode->jpath.innerjoinpath = inner_path;
2479  pathnode->jpath.joinrestrictinfo = restrict_clauses;
2480 
2481  final_cost_nestloop(root, pathnode, workspace, extra);
2482 
2483  return pathnode;
2484 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
void final_cost_nestloop(PlannerInfo *root, NestPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:3040
List * lappend(List *list, void *datum)
Definition: list.c:338
Bitmapset * get_param_path_clause_serials(Path *path)
Definition: relnode.c:1851
JoinPath jpath
Definition: pathnodes.h:2053
int rinfo_serial
Definition: pathnodes.h:2579

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

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

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

3548 {
3550 
3551  pathnode->path.pathtype = T_RecursiveUnion;
3552  pathnode->path.parent = rel;
3553  pathnode->path.pathtarget = target;
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  leftpath->parallel_safe && rightpath->parallel_safe;
3559  /* Foolish, but we'll do it like joins for now: */
3560  pathnode->path.parallel_workers = leftpath->parallel_workers;
3561  /* RecursiveUnion result is always unsorted */
3562  pathnode->path.pathkeys = NIL;
3563 
3564  pathnode->leftpath = leftpath;
3565  pathnode->rightpath = rightpath;
3566  pathnode->distinctList = distinctList;
3567  pathnode->wtParam = wtParam;
3568  pathnode->numGroups = numGroups;
3569 
3570  cost_recursive_union(&pathnode->path, leftpath, rightpath);
3571 
3572  return pathnode;
3573 }
void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
Definition: costsize.c:1785
Cardinality numGroups
Definition: pathnodes.h:2312

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

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

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

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

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

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

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

3488 {
3489  SetOpPath *pathnode = makeNode(SetOpPath);
3490 
3491  pathnode->path.pathtype = T_SetOp;
3492  pathnode->path.parent = rel;
3493  /* SetOp doesn't project, so use source path's pathtarget */
3494  pathnode->path.pathtarget = subpath->pathtarget;
3495  /* For now, assume we are above any joins, so no parameterization */
3496  pathnode->path.param_info = NULL;
3497  pathnode->path.parallel_aware = false;
3498  pathnode->path.parallel_safe = rel->consider_parallel &&
3499  subpath->parallel_safe;
3500  pathnode->path.parallel_workers = subpath->parallel_workers;
3501  /* SetOp preserves the input sort order if in sort mode */
3502  pathnode->path.pathkeys =
3503  (strategy == SETOP_SORTED) ? subpath->pathkeys : NIL;
3504 
3505  pathnode->subpath = subpath;
3506  pathnode->cmd = cmd;
3507  pathnode->strategy = strategy;
3508  pathnode->distinctList = distinctList;
3509  pathnode->flagColIdx = flagColIdx;
3510  pathnode->firstFlag = firstFlag;
3511  pathnode->numGroups = numGroups;
3512 
3513  /*
3514  * Charge one cpu_operator_cost per comparison per input tuple. We assume
3515  * all columns get compared at most of the tuples.
3516  */
3517  pathnode->path.startup_cost = subpath->startup_cost;
3518  pathnode->path.total_cost = subpath->total_cost +
3519  cpu_operator_cost * subpath->rows * list_length(distinctList);
3520  pathnode->path.rows = outputRows;
3521 
3522  return pathnode;
3523 }
double cpu_operator_cost
Definition: costsize.c:124
@ SETOP_SORTED
Definition: nodes.h:414
List * distinctList
Definition: pathnodes.h:2296
Cardinality numGroups
Definition: pathnodes.h:2299
int firstFlag
Definition: pathnodes.h:2298
Path * subpath
Definition: pathnodes.h:2293
SetOpCmd cmd
Definition: pathnodes.h:2294
Path path
Definition: pathnodes.h:2292
SetOpStrategy strategy
Definition: pathnodes.h:2295
AttrNumber flagColIdx
Definition: pathnodes.h:2297

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

2958 {
2959  SortPath *pathnode = makeNode(SortPath);
2960 
2961  pathnode->path.pathtype = T_Sort;
2962  pathnode->path.parent = rel;
2963  /* Sort doesn't project, so use source path's pathtarget */
2964  pathnode->path.pathtarget = subpath->pathtarget;
2965  /* For now, assume we are above any joins, so no parameterization */
2966  pathnode->path.param_info = NULL;
2967  pathnode->path.parallel_aware = false;
2968  pathnode->path.parallel_safe = rel->consider_parallel &&
2969  subpath->parallel_safe;
2970  pathnode->path.parallel_workers = subpath->parallel_workers;
2971  pathnode->path.pathkeys = pathkeys;
2972 
2973  pathnode->subpath = subpath;
2974 
2975  cost_sort(&pathnode->path, root, pathkeys,
2976  subpath->total_cost,
2977  subpath->rows,
2978  subpath->pathtarget->width,
2979  0.0, /* XXX comparison_cost shouldn't be 0? */
2980  work_mem, limit_tuples);
2981 
2982  return pathnode;
2983 }

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_to_grouping_rel(), add_paths_with_pathkeys_for_rel(), create_final_distinct_paths(), create_one_window_path(), create_ordered_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), gather_grouping_paths(), generate_nonunion_paths(), generate_useful_gather_paths(), and make_union_unique().

◆ create_subqueryscan_path()

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

Definition at line 2008 of file pathnode.c.

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

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

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

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:1329
List * tidrangequals
Definition: pathnodes.h:1810

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:1221
List * tidquals
Definition: pathnodes.h:1798
Path path
Definition: pathnodes.h:1797

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

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

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

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

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

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

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

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

References Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cost_windowagg(), list_length(), makeNode, NIL, WindowClause::orderClause, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, WindowClause::partitionClause, 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 2193 of file pathnode.c.

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

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

3872 {
3873  RelOptInfo *rel = path->parent;
3874 
3875  /* Can only increase, not decrease, path's parameterization */
3876  if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
3877  return NULL;
3878  switch (path->pathtype)
3879  {
3880  case T_SeqScan:
3881  return create_seqscan_path(root, rel, required_outer, 0);
3882  case T_SampleScan:
3883  return (Path *) create_samplescan_path(root, rel, required_outer);
3884  case T_IndexScan:
3885  case T_IndexOnlyScan:
3886  {
3887  IndexPath *ipath = (IndexPath *) path;
3888  IndexPath *newpath = makeNode(IndexPath);
3889 
3890  /*
3891  * We can't use create_index_path directly, and would not want
3892  * to because it would re-compute the indexqual conditions
3893  * which is wasted effort. Instead we hack things a bit:
3894  * flat-copy the path node, revise its param_info, and redo
3895  * the cost estimate.
3896  */
3897  memcpy(newpath, ipath, sizeof(IndexPath));
3898  newpath->path.param_info =
3899  get_baserel_parampathinfo(root, rel, required_outer);
3900  cost_index(newpath, root, loop_count, false);
3901  return (Path *) newpath;
3902  }
3903  case T_BitmapHeapScan:
3904  {
3905  BitmapHeapPath *bpath = (BitmapHeapPath *) path;
3906 
3907  return (Path *) create_bitmap_heap_path(root,
3908  rel,
3909  bpath->bitmapqual,
3910  required_outer,
3911  loop_count, 0);
3912  }
3913  case T_SubqueryScan:
3914  {
3915  SubqueryScanPath *spath = (SubqueryScanPath *) path;
3916  Path *subpath = spath->subpath;
3917  bool trivial_pathtarget;
3918 
3919  /*
3920  * If existing node has zero extra cost, we must have decided
3921  * its target is trivial. (The converse is not true, because
3922  * it might have a trivial target but quals to enforce; but in
3923  * that case the new node will too, so it doesn't matter
3924  * whether we get the right answer here.)
3925  */
3926  trivial_pathtarget =
3927  (subpath->total_cost == spath->path.total_cost);
3928 
3929  return (Path *) create_subqueryscan_path(root,
3930  rel,
3931  subpath,
3932  trivial_pathtarget,
3933  spath->path.pathkeys,
3934  required_outer);
3935  }
3936  case T_Result:
3937  /* Supported only for RTE_RESULT scan paths */
3938  if (IsA(path, Path))
3939  return create_resultscan_path(root, rel, required_outer);
3940  break;
3941  case T_Append:
3942  {
3943  AppendPath *apath = (AppendPath *) path;
3944  List *childpaths = NIL;
3945  List *partialpaths = NIL;
3946  int i;
3947  ListCell *lc;
3948 
3949  /* Reparameterize the children */
3950  i = 0;
3951  foreach(lc, apath->subpaths)
3952  {
3953  Path *spath = (Path *) lfirst(lc);
3954 
3955  spath = reparameterize_path(root, spath,
3956  required_outer,
3957  loop_count);
3958  if (spath == NULL)
3959  return NULL;
3960  /* We have to re-split the regular and partial paths */
3961  if (i < apath->first_partial_path)
3962  childpaths = lappend(childpaths, spath);
3963  else
3964  partialpaths = lappend(partialpaths, spath);
3965  i++;
3966  }
3967  return (Path *)
3968  create_append_path(root, rel, childpaths, partialpaths,
3969  apath->path.pathkeys, required_outer,
3970  apath->path.parallel_workers,
3971  apath->path.parallel_aware,
3972  -1);
3973  }
3974  case T_Material:
3975  {
3976  MaterialPath *mpath = (MaterialPath *) path;
3977  Path *spath = mpath->subpath;
3978 
3979  spath = reparameterize_path(root, spath,
3980  required_outer,
3981  loop_count);
3982  if (spath == NULL)
3983  return NULL;
3984  return (Path *) create_material_path(rel, spath);
3985  }
3986  case T_Memoize:
3987  {
3988  MemoizePath *mpath = (MemoizePath *) path;
3989  Path *spath = mpath->subpath;
3990 
3991  spath = reparameterize_path(root, spath,
3992  required_outer,
3993  loop_count);
3994  if (spath == NULL)
3995  return NULL;
3996  return (Path *) create_memoize_path(root, rel,
3997  spath,
3998  mpath->param_exprs,
3999  mpath->hash_operators,
4000  mpath->singlerow,
4001  mpath->binary_mode,
4002  mpath->calls);
4003  }
4004  default:
4005  break;
4006  }
4007  return NULL;
4008 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:332
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:1242
Path * create_resultscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Definition: pathnode.c:2167
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:1596
Path * reparameterize_path(PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
Definition: pathnode.c:3869
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
Definition: pathnode.c:2008
MaterialPath * create_material_path(RelOptInfo *rel, Path *subpath)
Definition: pathnode.c:1564
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 4030 of file pathnode.c.

4032 {
4033 
4034 #define FLAT_COPY_PATH(newnode, node, nodetype) \
4035  ( (newnode) = makeNode(nodetype), \
4036  memcpy((newnode), (node), sizeof(nodetype)) )
4037 
4038 #define ADJUST_CHILD_ATTRS(node) \
4039  ((node) = \
4040  (List *) adjust_appendrel_attrs_multilevel(root, (Node *) (node), \
4041  child_rel, \
4042  child_rel->top_parent))
4043 
4044 #define REPARAMETERIZE_CHILD_PATH(path) \
4045 do { \
4046  (path) = reparameterize_path_by_child(root, (path), child_rel); \
4047  if ((path) == NULL) \
4048  return NULL; \
4049 } while(0)
4050 
4051 #define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
4052 do { \
4053  if ((pathlist) != NIL) \
4054  { \
4055  (pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
4056  child_rel); \
4057  if ((pathlist) == NIL) \
4058  return NULL; \
4059  } \
4060 } while(0)
4061 
4062  Path *new_path;
4063  ParamPathInfo *new_ppi;
4064  ParamPathInfo *old_ppi;
4065  Relids required_outer;
4066 
4067  /*
4068  * If the path is not parameterized by parent of the given relation, it
4069  * doesn't need reparameterization.
4070  */
4071  if (!path->param_info ||
4072  !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4073  return path;
4074 
4075  /*
4076  * If possible, reparameterize the given path, making a copy.
4077  *
4078  * This function is currently only applied to the inner side of a nestloop
4079  * join that is being partitioned by the partitionwise-join code. Hence,
4080  * we need only support path types that plausibly arise in that context.
4081  * (In particular, supporting sorted path types would be a waste of code
4082  * and cycles: even if we translated them here, they'd just lose in
4083  * subsequent cost comparisons.) If we do see an unsupported path type,
4084  * that just means we won't be able to generate a partitionwise-join plan
4085  * using that path type.
4086  */
4087  switch (nodeTag(path))
4088  {
4089  case T_Path:
4090  FLAT_COPY_PATH(new_path, path, Path);
4091  break;
4092 
4093  case T_IndexPath:
4094  {
4095  IndexPath *ipath;
4096 
4097  FLAT_COPY_PATH(ipath, path, IndexPath);
4099  new_path = (Path *) ipath;
4100  }
4101  break;
4102 
4103  case T_BitmapHeapPath:
4104  {
4105  BitmapHeapPath *bhpath;
4106 
4107  FLAT_COPY_PATH(bhpath, path, BitmapHeapPath);
4109  new_path = (Path *) bhpath;
4110  }
4111  break;
4112 
4113  case T_BitmapAndPath:
4114  {
4115  BitmapAndPath *bapath;
4116 
4117  FLAT_COPY_PATH(bapath, path, BitmapAndPath);
4119  new_path = (Path *) bapath;
4120  }
4121  break;
4122 
4123  case T_BitmapOrPath:
4124  {
4125  BitmapOrPath *bopath;
4126 
4127  FLAT_COPY_PATH(bopath, path, BitmapOrPath);
4129  new_path = (Path *) bopath;
4130  }
4131  break;
4132 
4133  case T_ForeignPath:
4134  {
4135  ForeignPath *fpath;
4137 
4138  FLAT_COPY_PATH(fpath, path, ForeignPath);
4139  if (fpath->fdw_outerpath)
4141 
4142  /* Hand over to FDW if needed. */
4143  rfpc_func =
4144  path->parent->fdwroutine->ReparameterizeForeignPathByChild;
4145  if (rfpc_func)
4146  fpath->fdw_private = rfpc_func(root, fpath->fdw_private,
4147  child_rel);
4148  new_path = (Path *) fpath;
4149  }
4150  break;
4151 
4152  case T_CustomPath:
4153  {
4154  CustomPath *cpath;
4155 
4156  FLAT_COPY_PATH(cpath, path, CustomPath);
4158  if (cpath->methods &&
4160  cpath->custom_private =
4162  cpath->custom_private,
4163  child_rel);
4164  new_path = (Path *) cpath;
4165  }
4166  break;
4167 
4168  case T_NestPath:
4169  {
4170  JoinPath *jpath;
4171  NestPath *npath;
4172 
4173  FLAT_COPY_PATH(npath, path, NestPath);
4174 
4175  jpath = (JoinPath *) npath;
4179  new_path = (Path *) npath;
4180  }
4181  break;
4182 
4183  case T_MergePath:
4184  {
4185  JoinPath *jpath;
4186  MergePath *mpath;
4187 
4188  FLAT_COPY_PATH(mpath, path, MergePath);
4189 
4190  jpath = (JoinPath *) mpath;
4195  new_path = (Path *) mpath;
4196  }
4197  break;
4198 
4199  case T_HashPath:
4200  {
4201  JoinPath *jpath;
4202  HashPath *hpath;
4203 
4204  FLAT_COPY_PATH(hpath, path, HashPath);
4205 
4206  jpath = (JoinPath *) hpath;
4211  new_path = (Path *) hpath;
4212  }
4213  break;
4214 
4215  case T_AppendPath:
4216  {
4217  AppendPath *apath;
4218 
4219  FLAT_COPY_PATH(apath, path, AppendPath);
4221  new_path = (Path *) apath;
4222  }
4223  break;
4224 
4225  case T_MaterialPath:
4226  {
4227  MaterialPath *mpath;
4228 
4229  FLAT_COPY_PATH(mpath, path, MaterialPath);
4231  new_path = (Path *) mpath;
4232  }
4233  break;
4234 
4235  case T_MemoizePath:
4236  {
4237  MemoizePath *mpath;
4238 
4239  FLAT_COPY_PATH(mpath, path, MemoizePath);
4242  new_path = (Path *) mpath;
4243  }
4244  break;
4245 
4246  case T_GatherPath:
4247  {
4248  GatherPath *gpath;
4249 
4250  FLAT_COPY_PATH(gpath, path, GatherPath);
4252  new_path = (Path *) gpath;
4253  }
4254  break;
4255 
4256  default:
4257 
4258  /* We don't know how to reparameterize this path. */
4259  return NULL;
4260  }
4261 
4262  /*
4263  * Adjust the parameterization information, which refers to the topmost
4264  * parent. The topmost parent can be multiple levels away from the given
4265  * child, hence use multi-level expression adjustment routines.
4266  */
4267  old_ppi = new_path->param_info;
4268  required_outer =
4270  child_rel,
4271  child_rel->top_parent);
4272 
4273  /* If we already have a PPI for this parameterization, just return it */
4274  new_ppi = find_param_path_info(new_path->parent, required_outer);
4275 
4276  /*
4277  * If not, build a new one and link it to the list of PPIs. For the same
4278  * reason as explained in mark_dummy_rel(), allocate new PPI in the same
4279  * context the given RelOptInfo is in.
4280  */
4281  if (new_ppi == NULL)
4282  {
4283  MemoryContext oldcontext;
4284  RelOptInfo *rel = path->parent;
4285 
4286  oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel));
4287 
4288  new_ppi = makeNode(ParamPathInfo);
4289  new_ppi->ppi_req_outer = bms_copy(required_outer);
4290  new_ppi->ppi_rows = old_ppi->ppi_rows;
4291  new_ppi->ppi_clauses = old_ppi->ppi_clauses;
4292  ADJUST_CHILD_ATTRS(new_ppi->ppi_clauses);
4293  new_ppi->ppi_serials = bms_copy(old_ppi->ppi_serials);
4294  rel->ppilist = lappend(rel->ppilist, new_ppi);
4295 
4296  MemoryContextSwitchTo(oldcontext);
4297  }
4298  bms_free(required_outer);
4299 
4300  new_path->param_info = new_ppi;
4301 
4302  /*
4303  * Adjust the path target if the parent of the outer relation is
4304  * referenced in the targetlist. This can happen when only the parent of
4305  * outer relation is laterally referenced in this relation.
4306  */
4307  if (bms_overlap(path->parent->lateral_relids,
4308  child_rel->top_parent_relids))
4309  {
4310  new_path->pathtarget = copy_pathtarget(new_path->pathtarget);
4311  ADJUST_CHILD_ATTRS(new_path->pathtarget->exprs);
4312  }
4313 
4314  return new_path;
4315 }
Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition: appendinfo.c:587
void bms_free(Bitmapset *a)
Definition: bitmapset.c:209
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:1830
struct List *(* ReparameterizeCustomPathByChild)(PlannerInfo *root, List *custom_private, RelOptInfo *child_rel)
Definition: extensible.h:103
const struct CustomPathMethods * methods
Definition: pathnodes.h:1872
List * custom_paths
Definition: pathnodes.h:1870
List * custom_private
Definition: pathnodes.h:1871
Cardinality ppi_rows
Definition: pathnodes.h:1554
List * ppi_clauses
Definition: pathnodes.h:1555
Bitmapset * ppi_serials
Definition: pathnodes.h:1556
Relids ppi_req_outer
Definition: pathnodes.h:1553
List * ppilist
Definition: pathnodes.h:890
Relids top_parent_relids
Definition: pathnodes.h:994
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, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, 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 4322 of file pathnode.c.

4325 {
4326  ListCell *lc;
4327  List *result = NIL;
4328 
4329  foreach(lc, pathlist)
4330  {
4331  Path *path = reparameterize_path_by_child(root, lfirst(lc),
4332  child_rel);
4333 
4334  if (path == NULL)
4335  {
4336  list_free(result);
4337  return NIL;
4338  }
4339 
4340  result = lappend(result, path);
4341  }
4342 
4343  return result;
4344 }
void list_free(List *list)
Definition: list.c:1545

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  }
312  }
313  else
314  {
315  /* Unparameterized path, so consider it for cheapest slots */
316  if (cheapest_total_path == NULL)
317  {
318  cheapest_startup_path = cheapest_total_path = path;
319  continue;
320  }
321 
322  /*
323  * If we find two paths of identical costs, try to keep the
324  * better-sorted one. The paths might have unrelated sort
325  * orderings, in which case we can only guess which might be
326  * better to keep, but if one is superior then we definitely
327  * should keep that one.
328  */
329  cmp = compare_path_costs(cheapest_startup_path, path, STARTUP_COST);
330  if (cmp > 0 ||
331  (cmp == 0 &&
332  compare_pathkeys(cheapest_startup_path->pathkeys,
333  path->pathkeys) == PATHKEYS_BETTER2))
334  cheapest_startup_path = path;
335 
336  cmp = compare_path_costs(cheapest_total_path, path, TOTAL_COST);
337  if (cmp > 0 ||
338  (cmp == 0 &&
339  compare_pathkeys(cheapest_total_path->pathkeys,
340  path->pathkeys) == PATHKEYS_BETTER2))
341  cheapest_total_path = path;
342  }
343  }
344 
345  /* Add cheapest unparameterized path, if any, to parameterized_paths */
346  if (cheapest_total_path)
347  parameterized_paths = lcons(cheapest_total_path, parameterized_paths);
348 
349  /*
350  * If there is no unparameterized path, use the best parameterized path as
351  * cheapest_total_path (but not as cheapest_startup_path).
352  */
353  if (cheapest_total_path == NULL)
354  cheapest_total_path = best_param_path;
355  Assert(cheapest_total_path != NULL);
356 
357  parent_rel->cheapest_startup_path = cheapest_startup_path;
358  parent_rel->cheapest_total_path = cheapest_total_path;
359  parent_rel->cheapest_unique_path = NULL; /* computed only if needed */
360  parent_rel->cheapest_parameterized_paths = parameterized_paths;
361 }
@ BMS_DIFFERENT
Definition: bitmapset.h:65
List * lcons(void *datum, List *list)
Definition: list.c:494
List * cheapest_parameterized_paths
Definition: pathnodes.h:895
struct Path * cheapest_startup_path
Definition: pathnodes.h:892

References Assert(), BMS_DIFFERENT, BMS_EQUAL, BMS_SUBSET1, BMS_SUBSET2, bms_subset_compare(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, cmp(), compare_path_costs(), compare_pathkeys(), elog(), ERROR, IsA, lappend(), lcons(), lfirst, NIL, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER2, RelOptInfo::pathlist, STARTUP_COST, and TOTAL_COST.

Referenced by apply_scanjoin_target_to_paths(), create_distinct_paths(), create_grouping_paths(), create_ordinary_grouping_paths(), create_partial_distinct_paths(), create_partitionwise_grouping_paths(), create_window_paths(),