PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pathnode.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "executor/nodeSetOp.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/extensible.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/tlist.h"
#include "parser/parsetree.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 ADJUST_CHILD_ATTRS(node)
 
#define REPARAMETERIZE_CHILD_PATH(path)
 
#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist)
 
#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE(path)
 
#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE(pathlist)
 

Enumerations

enum  PathCostComparison { COSTS_EQUAL , COSTS_BETTER1 , COSTS_BETTER2 , COSTS_DIFFERENT }
 

Functions

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)
 
static bool pathlist_is_reparameterizable_by_child (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, int disabled_nodes, 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, int disabled_nodes, 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, int parallel_workers)
 
AppendPathcreate_append_path (PlannerInfo *root, RelOptInfo *rel, AppendPathInput input, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *child_append_relid_sets, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath, bool enabled)
 
MemoizePathcreate_memoize_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, Cardinality est_calls)
 
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, List *pathkeys, 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, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
ForeignPathcreate_foreign_join_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
ForeignPathcreate_foreign_upper_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
Relids calc_nestloop_required_outer (Relids outerrelids, Relids outer_paramrels, Relids innerrelids, Relids inner_paramrels)
 
Relids calc_non_nestloop_required_outer (Path *outer_path, Path *inner_path)
 
NestPathcreate_nestloop_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer)
 
MergePathcreate_mergejoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer, List *mergeclauses, List *outersortkeys, List *innersortkeys, int outer_presorted_keys)
 
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)
 
UniquePathcreate_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, List *runCondition, WindowClause *winclause, List *qual, bool topwindow)
 
SetOpPathcreate_setop_path (PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, SetOpCmd cmd, SetOpStrategy strategy, List *groupList, 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, List *resultRelations, List *updateColnosLists, List *withCheckOptionLists, List *returningLists, List *rowMarks, OnConflictExpr *onconflict, List *mergeActionLists, List *mergeJoinConditions, 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)
 
bool path_is_reparameterizable_by_child (Path *path, RelOptInfo *child_rel)
 

Macro Definition Documentation

◆ ADJUST_CHILD_ATTRS

#define ADJUST_CHILD_ATTRS (   node)
Value:
(Node *) (node), \
child_rel->top_parent))
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition appendinfo.c:592
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
Definition nodes.h:135

◆ CONSIDER_PATH_STARTUP_COST

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

◆ REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE

#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE (   pathlist)
Value:
do { \
return false; \
} while(0)
static bool pathlist_is_reparameterizable_by_child(List *pathlist, RelOptInfo *child_rel)
Definition pathnode.c:4489

◆ REJECT_IF_PATH_NOT_REPARAMETERIZABLE

#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE (   path)
Value:
do { \
return false; \
} while(0)
bool path_is_reparameterizable_by_child(Path *path, RelOptInfo *child_rel)
Definition pathnode.c:4329

◆ REPARAMETERIZE_CHILD_PATH

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

◆ REPARAMETERIZE_CHILD_PATH_LIST

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

◆ STD_FUZZ_FACTOR

#define STD_FUZZ_FACTOR   1.01

Definition at line 47 of file pathnode.c.

Enumeration Type Documentation

◆ PathCostComparison

Enumerator
COSTS_EQUAL 
COSTS_BETTER1 
COSTS_BETTER2 
COSTS_DIFFERENT 

Definition at line 34 of file pathnode.c.

35{
36 COSTS_EQUAL, /* path costs are fuzzily equal */
37 COSTS_BETTER1, /* first path is cheaper than second */
38 COSTS_BETTER2, /* second path is cheaper than first */
39 COSTS_DIFFERENT, /* neither path dominates the other on cost */
PathCostComparison
Definition pathnode.c:35
@ COSTS_EQUAL
Definition pathnode.c:36
@ COSTS_BETTER1
Definition pathnode.c:37
@ COSTS_BETTER2
Definition pathnode.c:38
@ COSTS_DIFFERENT
Definition pathnode.c:39

Function Documentation

◆ add_partial_path()

void add_partial_path ( RelOptInfo parent_rel,
Path new_path 
)

Definition at line 793 of file pathnode.c.

794{
795 bool accept_new = true; /* unless we find a superior old path */
796 int insert_at = 0; /* where to insert new item */
797 ListCell *p1;
798
799 /* Check for query cancel. */
801
802 /* Path to be added must be parallel safe. */
803 Assert(new_path->parallel_safe);
804
805 /* Relation should be OK for parallelism, too. */
806 Assert(parent_rel->consider_parallel);
807
808 /*
809 * As in add_path, throw out any paths which are dominated by the new
810 * path, but throw out the new path if some existing path dominates it.
811 */
812 foreach(p1, parent_rel->partial_pathlist)
813 {
814 Path *old_path = (Path *) lfirst(p1);
815 bool remove_old = false; /* unless new proves superior */
817
818 /* Compare pathkeys. */
819 keyscmp = compare_pathkeys(new_path->pathkeys, old_path->pathkeys);
820
821 /* Unless pathkeys are incompatible, keep just one of the two paths. */
823 {
824 if (unlikely(new_path->disabled_nodes != old_path->disabled_nodes))
825 {
826 if (new_path->disabled_nodes > old_path->disabled_nodes)
827 accept_new = false;
828 else
829 remove_old = true;
830 }
831 else if (new_path->total_cost > old_path->total_cost
833 {
834 /* New path costs more; keep it only if pathkeys are better. */
836 accept_new = false;
837 }
838 else if (old_path->total_cost > new_path->total_cost
840 {
841 /* Old path costs more; keep it only if pathkeys are better. */
843 remove_old = true;
844 }
845 else if (keyscmp == PATHKEYS_BETTER1)
846 {
847 /* Costs are about the same, new path has better pathkeys. */
848 remove_old = true;
849 }
850 else if (keyscmp == PATHKEYS_BETTER2)
851 {
852 /* Costs are about the same, old path has better pathkeys. */
853 accept_new = false;
854 }
855 else if (old_path->total_cost > new_path->total_cost * 1.0000000001)
856 {
857 /* Pathkeys are the same, and the old path costs more. */
858 remove_old = true;
859 }
860 else
861 {
862 /*
863 * Pathkeys are the same, and new path isn't materially
864 * cheaper.
865 */
866 accept_new = false;
867 }
868 }
869
870 /*
871 * Remove current element from partial_pathlist if dominated by new.
872 */
873 if (remove_old)
874 {
875 parent_rel->partial_pathlist =
876 foreach_delete_current(parent_rel->partial_pathlist, p1);
878 }
879 else
880 {
881 /* new belongs after this old path if it has cost >= old's */
882 if (new_path->total_cost >= old_path->total_cost)
884 }
885
886 /*
887 * If we found an old path that dominates new_path, we can quit
888 * scanning the partial_pathlist; we will not add new_path, and we
889 * assume new_path cannot dominate any later path.
890 */
891 if (!accept_new)
892 break;
893 }
894
895 if (accept_new)
896 {
897 /* Accept the new path: insert it at proper place */
898 parent_rel->partial_pathlist =
899 list_insert_nth(parent_rel->partial_pathlist, insert_at, new_path);
900 }
901 else
902 {
903 /* Reject and recycle the new path */
905 }
906}
#define Assert(condition)
Definition c.h:873
#define unlikely(x)
Definition c.h:412
List * list_insert_nth(List *list, int pos, void *datum)
Definition list.c:439
void pfree(void *pointer)
Definition mcxt.c:1616
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
PathKeysComparison compare_pathkeys(List *keys1, List *keys2)
Definition pathkeys.c:304
#define STD_FUZZ_FACTOR
Definition pathnode.c:47
PathKeysComparison
Definition paths.h:219
@ PATHKEYS_BETTER2
Definition paths.h:222
@ PATHKEYS_BETTER1
Definition paths.h:221
@ PATHKEYS_DIFFERENT
Definition paths.h:223
#define lfirst(lc)
Definition pg_list.h:172
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:391

References Assert, CHECK_FOR_INTERRUPTS, compare_pathkeys(), fb(), foreach_current_index, foreach_delete_current, lfirst, list_insert_nth(), PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, pfree(), STD_FUZZ_FACTOR, and unlikely.

Referenced by add_paths_to_append_rel(), build_index_paths(), build_setop_child_paths(), create_partial_bitmap_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), create_partial_unique_paths(), create_plain_partial_paths(), create_tidscan_paths(), generate_grouped_paths(), grouping_planner(), 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,
int  disabled_nodes,
Cost  total_cost,
List pathkeys 
)

Definition at line 919 of file pathnode.c.

921{
922 ListCell *p1;
923
924 /*
925 * Our goal here is twofold. First, we want to find out whether this path
926 * is clearly inferior to some existing partial path. If so, we want to
927 * reject it immediately. Second, we want to find out whether this path
928 * is clearly superior to some existing partial path -- at least, modulo
929 * final cost computations. If so, we definitely want to consider it.
930 *
931 * Unlike add_path(), we always compare pathkeys here. This is because we
932 * expect partial_pathlist to be very short, and getting a definitive
933 * answer at this stage avoids the need to call add_path_precheck.
934 */
935 foreach(p1, parent_rel->partial_pathlist)
936 {
937 Path *old_path = (Path *) lfirst(p1);
939
940 keyscmp = compare_pathkeys(pathkeys, old_path->pathkeys);
942 {
943 if (total_cost > old_path->total_cost * STD_FUZZ_FACTOR &&
945 return false;
946 if (old_path->total_cost > total_cost * STD_FUZZ_FACTOR &&
948 return true;
949 }
950 }
951
952 /*
953 * This path is neither clearly inferior to an existing partial path nor
954 * clearly good enough that it might replace one. Compare it to
955 * non-parallel plans. If it loses even before accounting for the cost of
956 * the Gather node, we should definitely reject it.
957 *
958 * Note that we pass the total_cost to add_path_precheck twice. This is
959 * because it's never advantageous to consider the startup cost of a
960 * partial path; the resulting plans, if run in parallel, will be run to
961 * completion.
962 */
963 if (!add_path_precheck(parent_rel, disabled_nodes, total_cost, total_cost,
964 pathkeys, NULL))
965 return false;
966
967 return true;
968}
bool add_path_precheck(RelOptInfo *parent_rel, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
Definition pathnode.c:686

References add_path_precheck(), compare_pathkeys(), fb(), lfirst, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, and STD_FUZZ_FACTOR.

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

460{
461 bool accept_new = true; /* unless we find a superior old path */
462 int insert_at = 0; /* where to insert new item */
464 ListCell *p1;
465
466 /*
467 * This is a convenient place to check for query cancel --- no part of the
468 * planner goes very long without calling add_path().
469 */
471
472 /* Pretend parameterized paths have no pathkeys, per comment above */
473 new_path_pathkeys = new_path->param_info ? NIL : new_path->pathkeys;
474
475 /*
476 * Loop to check proposed new path against old paths. Note it is possible
477 * for more than one old path to be tossed out because new_path dominates
478 * it.
479 */
480 foreach(p1, parent_rel->pathlist)
481 {
482 Path *old_path = (Path *) lfirst(p1);
483 bool remove_old = false; /* unless new proves superior */
487
488 /*
489 * Do a fuzzy cost comparison with standard fuzziness limit.
490 */
493
494 /*
495 * If the two paths compare differently for startup and total cost,
496 * then we want to keep both, and we can skip comparing pathkeys and
497 * required_outer rels. If they compare the same, proceed with the
498 * other comparisons. Row count is checked last. (We make the tests
499 * in this order because the cost comparison is most likely to turn
500 * out "different", and the pathkeys comparison next most likely. As
501 * explained above, row count very seldom makes a difference, so even
502 * though it's cheap to compare there's not much point in checking it
503 * earlier.)
504 */
506 {
507 /* Similarly check to see if either dominates on pathkeys */
509
510 old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
514 {
515 switch (costcmp)
516 {
517 case COSTS_EQUAL:
521 {
522 if ((outercmp == BMS_EQUAL ||
523 outercmp == BMS_SUBSET1) &&
524 new_path->rows <= old_path->rows &&
525 new_path->parallel_safe >= old_path->parallel_safe)
526 remove_old = true; /* new dominates old */
527 }
528 else if (keyscmp == PATHKEYS_BETTER2)
529 {
530 if ((outercmp == BMS_EQUAL ||
531 outercmp == BMS_SUBSET2) &&
532 new_path->rows >= old_path->rows &&
533 new_path->parallel_safe <= old_path->parallel_safe)
534 accept_new = false; /* old dominates new */
535 }
536 else /* keyscmp == PATHKEYS_EQUAL */
537 {
538 if (outercmp == BMS_EQUAL)
539 {
540 /*
541 * Same pathkeys and outer rels, and fuzzily
542 * the same cost, so keep just one; to decide
543 * which, first check parallel-safety, then
544 * rows, then do a fuzzy cost comparison with
545 * very small fuzz limit. (We used to do an
546 * exact cost comparison, but that results in
547 * annoying platform-specific plan variations
548 * due to roundoff in the cost estimates.) If
549 * things are still tied, arbitrarily keep
550 * only the old path. Notice that we will
551 * keep only the old path even if the
552 * less-fuzzy comparison decides the startup
553 * and total costs compare differently.
554 */
555 if (new_path->parallel_safe >
556 old_path->parallel_safe)
557 remove_old = true; /* new dominates old */
558 else if (new_path->parallel_safe <
559 old_path->parallel_safe)
560 accept_new = false; /* old dominates new */
561 else if (new_path->rows < old_path->rows)
562 remove_old = true; /* new dominates old */
563 else if (new_path->rows > old_path->rows)
564 accept_new = false; /* old dominates new */
566 old_path,
567 1.0000000001) == COSTS_BETTER1)
568 remove_old = true; /* new dominates old */
569 else
570 accept_new = false; /* old equals or
571 * dominates new */
572 }
573 else if (outercmp == BMS_SUBSET1 &&
574 new_path->rows <= old_path->rows &&
575 new_path->parallel_safe >= old_path->parallel_safe)
576 remove_old = true; /* new dominates old */
577 else if (outercmp == BMS_SUBSET2 &&
578 new_path->rows >= old_path->rows &&
579 new_path->parallel_safe <= old_path->parallel_safe)
580 accept_new = false; /* old dominates new */
581 /* else different parameterizations, keep both */
582 }
583 break;
584 case COSTS_BETTER1:
586 {
589 if ((outercmp == BMS_EQUAL ||
590 outercmp == BMS_SUBSET1) &&
591 new_path->rows <= old_path->rows &&
592 new_path->parallel_safe >= old_path->parallel_safe)
593 remove_old = true; /* new dominates old */
594 }
595 break;
596 case COSTS_BETTER2:
598 {
601 if ((outercmp == BMS_EQUAL ||
602 outercmp == BMS_SUBSET2) &&
603 new_path->rows >= old_path->rows &&
604 new_path->parallel_safe <= old_path->parallel_safe)
605 accept_new = false; /* old dominates new */
606 }
607 break;
608 case COSTS_DIFFERENT:
609
610 /*
611 * can't get here, but keep this case to keep compiler
612 * quiet
613 */
614 break;
615 }
616 }
617 }
618
619 /*
620 * Remove current element from pathlist if dominated by new.
621 */
622 if (remove_old)
623 {
624 parent_rel->pathlist = foreach_delete_current(parent_rel->pathlist,
625 p1);
626
627 /*
628 * Delete the data pointed-to by the deleted cell, if possible
629 */
630 if (!IsA(old_path, IndexPath))
632 }
633 else
634 {
635 /*
636 * new belongs after this old path if it has more disabled nodes
637 * or if it has the same number of nodes but a greater total cost
638 */
639 if (new_path->disabled_nodes > old_path->disabled_nodes ||
640 (new_path->disabled_nodes == old_path->disabled_nodes &&
641 new_path->total_cost >= old_path->total_cost))
643 }
644
645 /*
646 * If we found an old path that dominates new_path, we can quit
647 * scanning the pathlist; we will not add new_path, and we assume
648 * new_path cannot dominate any other elements of the pathlist.
649 */
650 if (!accept_new)
651 break;
652 }
653
654 if (accept_new)
655 {
656 /* Accept the new path: insert it at proper place in pathlist */
657 parent_rel->pathlist =
659 }
660 else
661 {
662 /* Reject and recycle the new path */
663 if (!IsA(new_path, IndexPath))
665 }
666}
BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:445
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:164
static PathCostComparison compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
Definition pathnode.c:181
#define PATH_REQ_OUTER(path)
Definition pathnodes.h:2001
Definition pg_list.h:54

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, fb(), foreach_current_index, foreach_delete_current, IsA, lfirst, list_insert_nth(), NIL, PATH_REQ_OUTER, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, pfree(), and STD_FUZZ_FACTOR.

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(), build_setop_child_paths(), BuildParameterizedTidPaths(), consider_groupingsets_paths(), create_degenerate_grouping_paths(), create_final_distinct_paths(), create_final_unique_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_grouped_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(), 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,
int  disabled_nodes,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer 
)

Definition at line 686 of file pathnode.c.

689{
691 bool consider_startup;
692 ListCell *p1;
693
694 /* Pretend parameterized paths have no pathkeys, per add_path policy */
695 new_path_pathkeys = required_outer ? NIL : pathkeys;
696
697 /* Decide whether new path's startup cost is interesting */
698 consider_startup = required_outer ? parent_rel->consider_param_startup : parent_rel->consider_startup;
699
700 foreach(p1, parent_rel->pathlist)
701 {
702 Path *old_path = (Path *) lfirst(p1);
704
705 /*
706 * Since the pathlist is sorted by disabled_nodes and then by
707 * total_cost, we can stop looking once we reach a path with more
708 * disabled nodes, or the same number of disabled nodes plus a
709 * total_cost larger than the new path's.
710 */
711 if (unlikely(old_path->disabled_nodes != disabled_nodes))
712 {
713 if (disabled_nodes < old_path->disabled_nodes)
714 break;
715 }
716 else if (total_cost <= old_path->total_cost * STD_FUZZ_FACTOR)
717 break;
718
719 /*
720 * We are looking for an old_path with the same parameterization (and
721 * by assumption the same rowcount) that dominates the new path on
722 * pathkeys as well as both cost metrics. If we find one, we can
723 * reject the new path.
724 *
725 * Cost comparisons here should match compare_path_costs_fuzzily.
726 */
727 /* new path can win on startup cost only if consider_startup */
728 if (startup_cost > old_path->startup_cost * STD_FUZZ_FACTOR ||
729 !consider_startup)
730 {
731 /* new path loses on cost, so check pathkeys... */
733
734 old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
737 if (keyscmp == PATHKEYS_EQUAL ||
739 {
740 /* new path does not win on pathkeys... */
742 {
743 /* Found an old path that dominates the new one */
744 return false;
745 }
746 }
747 }
748 }
749
750 return true;
751}
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:142
@ PATHKEYS_EQUAL
Definition paths.h:220

References bms_equal(), compare_pathkeys(), fb(), lfirst, NIL, PATH_REQ_OUTER, PATHKEYS_BETTER2, PATHKEYS_EQUAL, STD_FUZZ_FACTOR, and unlikely.

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

3800{
3801 double input_rows = *rows;
3802 Cost input_startup_cost = *startup_cost;
3803 Cost input_total_cost = *total_cost;
3804
3805 if (offset_est != 0)
3806 {
3807 double offset_rows;
3808
3809 if (offset_est > 0)
3810 offset_rows = (double) offset_est;
3811 else
3813 if (offset_rows > *rows)
3814 offset_rows = *rows;
3815 if (input_rows > 0)
3816 *startup_cost +=
3819 *rows -= offset_rows;
3820 if (*rows < 1)
3821 *rows = 1;
3822 }
3823
3824 if (count_est != 0)
3825 {
3826 double count_rows;
3827
3828 if (count_est > 0)
3829 count_rows = (double) count_est;
3830 else
3832 if (count_rows > *rows)
3833 count_rows = *rows;
3834 if (input_rows > 0)
3835 *total_cost = *startup_cost +
3838 *rows = count_rows;
3839 if (*rows < 1)
3840 *rows = 1;
3841 }
3842}
double clamp_row_est(double nrows)
Definition costsize.c:213
double Cost
Definition nodes.h:261

References clamp_row_est(), and fb().

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

1454{
1455 Path *path1 = (Path *) lfirst(a);
1456 Path *path2 = (Path *) lfirst(b);
1457 int cmp;
1458
1460 if (cmp != 0)
1461 return -cmp;
1462 return bms_compare(path1->parent->relids, path2->parent->relids);
1463}
int bms_compare(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:183
int b
Definition isn.c:74
int a
Definition isn.c:73
int compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
Definition pathnode.c:68
@ STARTUP_COST
Definition pathnodes.h:111
static int cmp(const chr *x, const chr *y, size_t len)

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

1432{
1433 Path *path1 = (Path *) lfirst(a);
1434 Path *path2 = (Path *) lfirst(b);
1435 int cmp;
1436
1438 if (cmp != 0)
1439 return -cmp;
1440 return bms_compare(path1->parent->relids, path2->parent->relids);
1441}
@ TOTAL_COST
Definition pathnodes.h:111

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

2647{
2649
2650 /*
2651 * If given path can't project, we might need a Result node, so make a
2652 * separate ProjectionPath.
2653 */
2654 if (!is_projection_capable_path(path))
2655 return (Path *) create_projection_path(root, rel, path, target);
2656
2657 /*
2658 * We can just jam the desired tlist into the existing path, being sure to
2659 * update its cost estimates appropriately.
2660 */
2661 oldcost = path->pathtarget->cost;
2662 path->pathtarget = target;
2663
2664 path->startup_cost += target->cost.startup - oldcost.startup;
2665 path->total_cost += target->cost.startup - oldcost.startup +
2666 (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
2667
2668 /*
2669 * If the path happens to be a Gather or GatherMerge path, we'd like to
2670 * arrange for the subpath to return the required target list so that
2671 * workers can help project. But if there is something that is not
2672 * parallel-safe in the target expressions, then we can't.
2673 */
2674 if ((IsA(path, GatherPath) || IsA(path, GatherMergePath)) &&
2675 is_parallel_safe(root, (Node *) target->exprs))
2676 {
2677 /*
2678 * We always use create_projection_path here, even if the subpath is
2679 * projection-capable, so as to avoid modifying the subpath in place.
2680 * It seems unlikely at present that there could be any other
2681 * references to the subpath, but better safe than sorry.
2682 *
2683 * Note that we don't change the parallel path's cost estimates; it
2684 * might be appropriate to do so, to reflect the fact that the bulk of
2685 * the target evaluation will happen in workers.
2686 */
2687 if (IsA(path, GatherPath))
2688 {
2689 GatherPath *gpath = (GatherPath *) path;
2690
2691 gpath->subpath = (Path *)
2693 gpath->subpath->parent,
2694 gpath->subpath,
2695 target);
2696 }
2697 else
2698 {
2700
2701 gmpath->subpath = (Path *)
2703 gmpath->subpath->parent,
2704 gmpath->subpath,
2705 target);
2706 }
2707 }
2708 else if (path->parallel_safe &&
2709 !is_parallel_safe(root, (Node *) target->exprs))
2710 {
2711 /*
2712 * We're inserting a parallel-restricted target list into a path
2713 * currently marked parallel-safe, so we have to mark it as no longer
2714 * safe.
2715 */
2716 path->parallel_safe = false;
2717 }
2718
2719 return path;
2720}
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition clauses.c:762
bool is_projection_capable_path(Path *path)
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition pathnode.c:2534
Path * subpath
Definition pathnodes.h:2358
List * exprs
Definition pathnodes.h:1864
QualCost cost
Definition pathnodes.h:1870
Cardinality rows
Definition pathnodes.h:1991
Cost startup_cost
Definition pathnodes.h:1993
Cost total_cost
Definition pathnodes.h:1994
bool parallel_safe
Definition pathnodes.h:1986
Cost per_tuple
Definition pathnodes.h:121
Cost startup
Definition pathnodes.h:120

References PathTarget::cost, create_projection_path(), PathTarget::exprs, fb(), is_parallel_safe(), is_projection_capable_path(), IsA, Path::parallel_safe, QualCost::per_tuple, root, Path::rows, QualCost::startup, Path::startup_cost, 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 2224 of file pathnode.c.

2228{
2230
2231 /* inner_path can require rels from outer path, but not vice versa */
2233 /* easy case if inner path is not parameterized */
2234 if (!inner_paramrels)
2235 return bms_copy(outer_paramrels);
2236 /* else, form the union ... */
2238 /* ... and remove any mention of now-satisfied outer rels */
2240 outerrelids);
2241 return required_outer;
2242}
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1160
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:251
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:581
Bitmapset * bms_copy(const Bitmapset *a)
Definition bitmapset.c:122

References Assert, bms_copy(), bms_del_members(), bms_overlap(), bms_union(), and fb().

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

2252{
2256 Relids outerrelids PG_USED_FOR_ASSERTS_ONLY;
2258
2259 /*
2260 * Any parameterization of the input paths refers to topmost parents of
2261 * the relevant relations, because reparameterize_path_by_child() hasn't
2262 * been called yet. So we must consider topmost parents of the relations
2263 * being joined, too, while checking for disallowed parameterization
2264 * cases.
2265 */
2266 if (inner_path->parent->top_parent_relids)
2267 innerrelids = inner_path->parent->top_parent_relids;
2268 else
2269 innerrelids = inner_path->parent->relids;
2270
2271 if (outer_path->parent->top_parent_relids)
2272 outerrelids = outer_path->parent->top_parent_relids;
2273 else
2274 outerrelids = outer_path->parent->relids;
2275
2276 /* neither path can require rels from the other */
2278 Assert(!bms_overlap(inner_paramrels, outerrelids));
2279 /* form the union ... */
2281 /* we do not need an explicit test for empty; bms_union gets it right */
2282 return required_outer;
2283}
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:223

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

Referenced by try_hashjoin_path(), and try_mergejoin_path().

◆ compare_fractional_path_costs()

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

Definition at line 123 of file pathnode.c.

125{
126 Cost cost1,
127 cost2;
128
129 /* Number of disabled nodes, if different, trumps all else. */
130 if (unlikely(path1->disabled_nodes != path2->disabled_nodes))
131 {
132 if (path1->disabled_nodes < path2->disabled_nodes)
133 return -1;
134 else
135 return +1;
136 }
137
140 cost1 = path1->startup_cost +
141 fraction * (path1->total_cost - path1->startup_cost);
142 cost2 = path2->startup_cost +
143 fraction * (path2->total_cost - path2->startup_cost);
144 if (cost1 < cost2)
145 return -1;
146 if (cost1 > cost2)
147 return +1;
148 return 0;
149}

References compare_path_costs(), fb(), TOTAL_COST, and unlikely.

Referenced by 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 68 of file pathnode.c.

69{
70 /* Number of disabled nodes, if different, trumps all else. */
71 if (unlikely(path1->disabled_nodes != path2->disabled_nodes))
72 {
73 if (path1->disabled_nodes < path2->disabled_nodes)
74 return -1;
75 else
76 return +1;
77 }
78
80 {
81 if (path1->startup_cost < path2->startup_cost)
82 return -1;
83 if (path1->startup_cost > path2->startup_cost)
84 return +1;
85
86 /*
87 * If paths have the same startup cost (not at all unlikely), order
88 * them by total cost.
89 */
90 if (path1->total_cost < path2->total_cost)
91 return -1;
92 if (path1->total_cost > path2->total_cost)
93 return +1;
94 }
95 else
96 {
97 if (path1->total_cost < path2->total_cost)
98 return -1;
99 if (path1->total_cost > path2->total_cost)
100 return +1;
101
102 /*
103 * If paths have the same total cost, order them by startup cost.
104 */
105 if (path1->startup_cost < path2->startup_cost)
106 return -1;
107 if (path1->startup_cost > path2->startup_cost)
108 return +1;
109 }
110 return 0;
111}

References fb(), STARTUP_COST, and unlikely.

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

182{
183#define CONSIDER_PATH_STARTUP_COST(p) \
184 ((p)->param_info == NULL ? (p)->parent->consider_startup : (p)->parent->consider_param_startup)
185
186 /* Number of disabled nodes, if different, trumps all else. */
187 if (unlikely(path1->disabled_nodes != path2->disabled_nodes))
188 {
189 if (path1->disabled_nodes < path2->disabled_nodes)
190 return COSTS_BETTER1;
191 else
192 return COSTS_BETTER2;
193 }
194
195 /*
196 * Check total cost first since it's more likely to be different; many
197 * paths have zero startup cost.
198 */
199 if (path1->total_cost > path2->total_cost * fuzz_factor)
200 {
201 /* path1 fuzzily worse on total cost */
203 path2->startup_cost > path1->startup_cost * fuzz_factor)
204 {
205 /* ... but path2 fuzzily worse on startup, so DIFFERENT */
206 return COSTS_DIFFERENT;
207 }
208 /* else path2 dominates */
209 return COSTS_BETTER2;
210 }
211 if (path2->total_cost > path1->total_cost * fuzz_factor)
212 {
213 /* path2 fuzzily worse on total cost */
215 path1->startup_cost > path2->startup_cost * fuzz_factor)
216 {
217 /* ... but path1 fuzzily worse on startup, so DIFFERENT */
218 return COSTS_DIFFERENT;
219 }
220 /* else path1 dominates */
221 return COSTS_BETTER1;
222 }
223 /* fuzzily the same on total cost ... */
224 if (path1->startup_cost > path2->startup_cost * fuzz_factor)
225 {
226 /* ... but path1 fuzzily worse on startup, so path2 wins */
227 return COSTS_BETTER2;
228 }
229 if (path2->startup_cost > path1->startup_cost * fuzz_factor)
230 {
231 /* ... but path2 fuzzily worse on startup, so path1 wins */
232 return COSTS_BETTER1;
233 }
234 /* fuzzily the same on both costs */
235 return COSTS_EQUAL;
236
237#undef CONSIDER_PATH_STARTUP_COST
238}
#define CONSIDER_PATH_STARTUP_COST(p)

References CONSIDER_PATH_STARTUP_COST, COSTS_BETTER1, COSTS_BETTER2, COSTS_DIFFERENT, COSTS_EQUAL, fb(), and unlikely.

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

3014{
3016
3017 pathnode->path.pathtype = T_Agg;
3018 pathnode->path.parent = rel;
3019 pathnode->path.pathtarget = target;
3020 pathnode->path.param_info = subpath->param_info;
3021 pathnode->path.parallel_aware = false;
3022 pathnode->path.parallel_safe = rel->consider_parallel &&
3023 subpath->parallel_safe;
3024 pathnode->path.parallel_workers = subpath->parallel_workers;
3025
3026 if (aggstrategy == AGG_SORTED)
3027 {
3028 /*
3029 * Attempt to preserve the order of the subpath. Additional pathkeys
3030 * may have been added in adjust_group_pathkeys_for_groupagg() to
3031 * support ORDER BY / DISTINCT aggregates. Pathkeys added there
3032 * belong to columns within the aggregate function, so we must strip
3033 * these additional pathkeys off as those columns are unavailable
3034 * above the aggregate node.
3035 */
3036 if (list_length(subpath->pathkeys) > root->num_groupby_pathkeys)
3037 pathnode->path.pathkeys = list_copy_head(subpath->pathkeys,
3038 root->num_groupby_pathkeys);
3039 else
3040 pathnode->path.pathkeys = subpath->pathkeys; /* preserves order */
3041 }
3042 else
3043 pathnode->path.pathkeys = NIL; /* output is unordered */
3044
3045 pathnode->subpath = subpath;
3046
3047 pathnode->aggstrategy = aggstrategy;
3048 pathnode->aggsplit = aggsplit;
3049 pathnode->numGroups = numGroups;
3050 pathnode->transitionSpace = aggcosts ? aggcosts->transitionSpace : 0;
3051 pathnode->groupClause = groupClause;
3052 pathnode->qual = qual;
3053
3054 cost_agg(&pathnode->path, root,
3055 aggstrategy, aggcosts,
3056 list_length(groupClause), numGroups,
3057 qual,
3058 subpath->disabled_nodes,
3059 subpath->startup_cost, subpath->total_cost,
3060 subpath->rows, subpath->pathtarget->width);
3061
3062 /* add tlist eval cost for each output row */
3063 pathnode->path.startup_cost += target->cost.startup;
3064 pathnode->path.total_cost += target->cost.startup +
3065 target->cost.per_tuple * pathnode->path.rows;
3066
3067 return pathnode;
3068}
void cost_agg(Path *path, PlannerInfo *root, AggStrategy aggstrategy, const AggClauseCosts *aggcosts, int numGroupCols, double numGroups, List *quals, int disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double input_tuples, double input_width)
Definition costsize.c:2787
List * list_copy_head(const List *oldlist, int len)
Definition list.c:1593
Datum subpath(PG_FUNCTION_ARGS)
Definition ltree_op.c:311
@ AGG_SORTED
Definition nodes.h:365
#define makeNode(_type_)
Definition nodes.h:161
static int list_length(const List *l)
Definition pg_list.h:152
bool consider_parallel
Definition pathnodes.h:1025

References AGG_SORTED, RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), fb(), list_copy_head(), list_length(), makeNode, NIL, QualCost::per_tuple, root, QualCost::startup, and subpath().

Referenced by add_paths_to_grouping_rel(), create_final_distinct_paths(), create_final_unique_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), create_partial_unique_paths(), generate_grouped_paths(), and generate_union_paths().

◆ create_append_path()

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

Definition at line 1299 of file pathnode.c.

1305{
1307 ListCell *l;
1308
1309 Assert(!parallel_aware || parallel_workers > 0);
1310
1311 pathnode->child_append_relid_sets = input.child_append_relid_sets;
1312 pathnode->path.pathtype = T_Append;
1313 pathnode->path.parent = rel;
1314 pathnode->path.pathtarget = rel->reltarget;
1315
1316 /*
1317 * If this is for a baserel (not a join or non-leaf partition), we prefer
1318 * to apply get_baserel_parampathinfo to construct a full ParamPathInfo
1319 * for the path. This supports building a Memoize path atop this path,
1320 * and if this is a partitioned table the info may be useful for run-time
1321 * pruning (cf make_partition_pruneinfo()).
1322 *
1323 * However, if we don't have "root" then that won't work and we fall back
1324 * on the simpler get_appendrel_parampathinfo. There's no point in doing
1325 * the more expensive thing for a dummy path, either.
1326 */
1327 if (rel->reloptkind == RELOPT_BASEREL && root && input.subpaths != NIL)
1328 pathnode->path.param_info = get_baserel_parampathinfo(root,
1329 rel,
1331 else
1332 pathnode->path.param_info = get_appendrel_parampathinfo(rel,
1334
1335 pathnode->path.parallel_aware = parallel_aware;
1336 pathnode->path.parallel_safe = rel->consider_parallel;
1337 pathnode->path.parallel_workers = parallel_workers;
1338 pathnode->path.pathkeys = pathkeys;
1339
1340 /*
1341 * For parallel append, non-partial paths are sorted by descending total
1342 * costs. That way, the total time to finish all non-partial paths is
1343 * minimized. Also, the partial paths are sorted by descending startup
1344 * costs. There may be some paths that require to do startup work by a
1345 * single worker. In such case, it's better for workers to choose the
1346 * expensive ones first, whereas the leader should choose the cheapest
1347 * startup plan.
1348 */
1349 if (pathnode->path.parallel_aware)
1350 {
1351 /*
1352 * We mustn't fiddle with the order of subpaths when the Append has
1353 * pathkeys. The order they're listed in is critical to keeping the
1354 * pathkeys valid.
1355 */
1356 Assert(pathkeys == NIL);
1357
1359 list_sort(input.partial_subpaths, append_startup_cost_compare);
1360 }
1361 pathnode->first_partial_path = list_length(input.subpaths);
1362 pathnode->subpaths = list_concat(input.subpaths, input.partial_subpaths);
1363
1364 /*
1365 * Apply query-wide LIMIT if known and path is for sole base relation.
1366 * (Handling this at this low level is a bit klugy.)
1367 */
1368 if (root != NULL && bms_equal(rel->relids, root->all_query_rels))
1369 pathnode->limit_tuples = root->limit_tuples;
1370 else
1371 pathnode->limit_tuples = -1.0;
1372
1373 foreach(l, pathnode->subpaths)
1374 {
1375 Path *subpath = (Path *) lfirst(l);
1376
1377 pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1378 subpath->parallel_safe;
1379
1380 /* All child paths must have same parameterization */
1382 }
1383
1384 Assert(!parallel_aware || pathnode->path.parallel_safe);
1385
1386 /*
1387 * If there's exactly one child path then the output of the Append is
1388 * necessarily ordered the same as the child's, so we can inherit the
1389 * child's pathkeys if any, overriding whatever the caller might've said.
1390 * Furthermore, if the child's parallel awareness matches the Append's,
1391 * then the Append is a no-op and will be discarded later (in setrefs.c).
1392 * Then we can inherit the child's size and cost too, effectively charging
1393 * zero for the Append. Otherwise, we must do the normal costsize
1394 * calculation.
1395 */
1396 if (list_length(pathnode->subpaths) == 1)
1397 {
1398 Path *child = (Path *) linitial(pathnode->subpaths);
1399
1400 if (child->parallel_aware == parallel_aware)
1401 {
1402 pathnode->path.rows = child->rows;
1403 pathnode->path.startup_cost = child->startup_cost;
1404 pathnode->path.total_cost = child->total_cost;
1405 }
1406 else
1408 /* Must do this last, else cost_append complains */
1409 pathnode->path.pathkeys = child->pathkeys;
1410 }
1411 else
1413
1414 /* If the caller provided a row estimate, override the computed value. */
1415 if (rows >= 0)
1416 pathnode->path.rows = rows;
1417
1418 return pathnode;
1419}
void cost_append(AppendPath *apath, PlannerInfo *root)
Definition costsize.c:2310
FILE * input
void list_sort(List *list, list_sort_comparator cmp)
Definition list.c:1674
List * list_concat(List *list1, const List *list2)
Definition list.c:561
static int append_startup_cost_compare(const ListCell *a, const ListCell *b)
Definition pathnode.c:1453
static int append_total_cost_compare(const ListCell *a, const ListCell *b)
Definition pathnode.c:1431
@ RELOPT_BASEREL
Definition pathnodes.h:965
#define linitial(l)
Definition pg_list.h:178
ParamPathInfo * get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
Definition relnode.c:2004
ParamPathInfo * get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
Definition relnode.c:1693
List * pathkeys
Definition pathnodes.h:1997
bool parallel_aware
Definition pathnodes.h:1984
Relids relids
Definition pathnodes.h:1009
struct PathTarget * reltarget
Definition pathnodes.h:1033
RelOptKind reloptkind
Definition pathnodes.h:1003

References append_startup_cost_compare(), append_total_cost_compare(), Assert, bms_equal(), RelOptInfo::consider_parallel, cost_append(), fb(), get_appendrel_parampathinfo(), get_baserel_parampathinfo(), input, lfirst, linitial, list_concat(), list_length(), list_sort(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, PATH_REQ_OUTER, Path::pathkeys, RelOptInfo::relids, RELOPT_BASEREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, root, Path::rows, Path::startup_cost, subpath(), 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 1129 of file pathnode.c.

1132{
1135 ListCell *lc;
1136
1137 pathnode->path.pathtype = T_BitmapAnd;
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
1151 PATH_REQ_OUTER(bitmapqual));
1152 }
1153 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
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: */
1172
1173 return pathnode;
1174}
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:916
void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
Definition costsize.c:1157

References bms_add_members(), RelOptInfo::consider_parallel, cost_bitmap_and_node(), fb(), get_baserel_parampathinfo(), lfirst, makeNode, NIL, PATH_REQ_OUTER, RelOptInfo::reltarget, and root.

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

1102{
1104
1105 pathnode->path.pathtype = T_BitmapHeapScan;
1106 pathnode->path.parent = rel;
1107 pathnode->path.pathtarget = rel->reltarget;
1108 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1110 pathnode->path.parallel_aware = (parallel_degree > 0);
1111 pathnode->path.parallel_safe = rel->consider_parallel;
1112 pathnode->path.parallel_workers = parallel_degree;
1113 pathnode->path.pathkeys = NIL; /* always unordered */
1114
1115 pathnode->bitmapqual = bitmapqual;
1116
1117 cost_bitmap_heap_scan(&pathnode->path, root, rel,
1118 pathnode->path.param_info,
1119 bitmapqual, loop_count);
1120
1121 return pathnode;
1122}
void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, Path *bitmapqual, double loop_count)
Definition costsize.c:1011

References RelOptInfo::consider_parallel, cost_bitmap_heap_scan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

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

1184{
1187 ListCell *lc;
1188
1189 pathnode->path.pathtype = T_BitmapOr;
1190 pathnode->path.parent = rel;
1191 pathnode->path.pathtarget = rel->reltarget;
1192
1193 /*
1194 * Identify the required outer rels as the union of what the child paths
1195 * depend on. (Alternatively, we could insist that the caller pass this
1196 * in, but it's more convenient and reliable to compute it here.)
1197 */
1198 foreach(lc, bitmapquals)
1199 {
1200 Path *bitmapqual = (Path *) lfirst(lc);
1201
1203 PATH_REQ_OUTER(bitmapqual));
1204 }
1205 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1207
1208 /*
1209 * Currently, a BitmapHeapPath, BitmapAndPath, or BitmapOrPath will be
1210 * parallel-safe if and only if rel->consider_parallel is set. So, we can
1211 * set the flag for this path based only on the relation-level flag,
1212 * without actually iterating over the list of children.
1213 */
1214 pathnode->path.parallel_aware = false;
1215 pathnode->path.parallel_safe = rel->consider_parallel;
1216 pathnode->path.parallel_workers = 0;
1217
1218 pathnode->path.pathkeys = NIL; /* always unordered */
1219
1220 pathnode->bitmapquals = bitmapquals;
1221
1222 /* this sets bitmapselectivity as well as the regular cost fields: */
1224
1225 return pathnode;
1226}
void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
Definition costsize.c:1202

References bms_add_members(), RelOptInfo::consider_parallel, cost_bitmap_or_node(), fb(), get_baserel_parampathinfo(), lfirst, makeNode, NIL, PATH_REQ_OUTER, RelOptInfo::reltarget, and root.

Referenced by generate_bitmap_or_paths().

◆ create_ctescan_path()

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

Definition at line 1964 of file pathnode.c.

1966{
1968
1969 pathnode->pathtype = T_CteScan;
1970 pathnode->parent = rel;
1971 pathnode->pathtarget = rel->reltarget;
1972 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1974 pathnode->parallel_aware = false;
1975 pathnode->parallel_safe = rel->consider_parallel;
1976 pathnode->parallel_workers = 0;
1977 pathnode->pathkeys = pathkeys;
1978
1979 cost_ctescan(pathnode, root, rel, pathnode->param_info);
1980
1981 return pathnode;
1982}
void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1744

References RelOptInfo::consider_parallel, cost_ctescan(), fb(), get_baserel_parampathinfo(), makeNode, RelOptInfo::reltarget, and root.

Referenced by set_cte_pathlist().

◆ create_foreign_join_path()

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

Definition at line 2123 of file pathnode.c.

2132{
2134
2135 /*
2136 * We should use get_joinrel_parampathinfo to handle parameterized paths,
2137 * but the API of this function doesn't support it, and existing
2138 * extensions aren't yet trying to build such paths anyway. For the
2139 * moment just throw an error if someone tries it; eventually we should
2140 * revisit this.
2141 */
2143 elog(ERROR, "parameterized foreign joins are not supported yet");
2144
2145 pathnode->path.pathtype = T_ForeignScan;
2146 pathnode->path.parent = rel;
2147 pathnode->path.pathtarget = target ? target : rel->reltarget;
2148 pathnode->path.param_info = NULL; /* XXX see above */
2149 pathnode->path.parallel_aware = false;
2150 pathnode->path.parallel_safe = rel->consider_parallel;
2151 pathnode->path.parallel_workers = 0;
2152 pathnode->path.rows = rows;
2153 pathnode->path.disabled_nodes = disabled_nodes;
2154 pathnode->path.startup_cost = startup_cost;
2155 pathnode->path.total_cost = total_cost;
2156 pathnode->path.pathkeys = pathkeys;
2157
2158 pathnode->fdw_outerpath = fdw_outerpath;
2159 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2160 pathnode->fdw_private = fdw_private;
2161
2162 return pathnode;
2163}
#define bms_is_empty(a)
Definition bitmapset.h:118
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
Relids lateral_relids
Definition pathnodes.h:1052

References bms_is_empty, RelOptInfo::consider_parallel, elog, ERROR, fb(), RelOptInfo::lateral_relids, makeNode, and RelOptInfo::reltarget.

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,
int  disabled_nodes,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Path fdw_outerpath,
List fdw_restrictinfo,
List fdw_private 
)

Definition at line 2177 of file pathnode.c.

2185{
2187
2188 /*
2189 * Upper relations should never have any lateral references, since joining
2190 * is complete.
2191 */
2193
2194 pathnode->path.pathtype = T_ForeignScan;
2195 pathnode->path.parent = rel;
2196 pathnode->path.pathtarget = target ? target : rel->reltarget;
2197 pathnode->path.param_info = NULL;
2198 pathnode->path.parallel_aware = false;
2199 pathnode->path.parallel_safe = rel->consider_parallel;
2200 pathnode->path.parallel_workers = 0;
2201 pathnode->path.rows = rows;
2202 pathnode->path.disabled_nodes = disabled_nodes;
2203 pathnode->path.startup_cost = startup_cost;
2204 pathnode->path.total_cost = total_cost;
2205 pathnode->path.pathkeys = pathkeys;
2206
2207 pathnode->fdw_outerpath = fdw_outerpath;
2208 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2209 pathnode->fdw_private = fdw_private;
2210
2211 return pathnode;
2212}

References Assert, bms_is_empty, RelOptInfo::consider_parallel, fb(), RelOptInfo::lateral_relids, makeNode, and RelOptInfo::reltarget.

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,
int  disabled_nodes,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer,
Path fdw_outerpath,
List fdw_restrictinfo,
List fdw_private 
)

Definition at line 2075 of file pathnode.c.

2084{
2086
2087 /* Historically some FDWs were confused about when to use this */
2088 Assert(IS_SIMPLE_REL(rel));
2089
2090 pathnode->path.pathtype = T_ForeignScan;
2091 pathnode->path.parent = rel;
2092 pathnode->path.pathtarget = target ? target : rel->reltarget;
2093 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
2095 pathnode->path.parallel_aware = false;
2096 pathnode->path.parallel_safe = rel->consider_parallel;
2097 pathnode->path.parallel_workers = 0;
2098 pathnode->path.rows = rows;
2099 pathnode->path.disabled_nodes = disabled_nodes;
2100 pathnode->path.startup_cost = startup_cost;
2101 pathnode->path.total_cost = total_cost;
2102 pathnode->path.pathkeys = pathkeys;
2103
2104 pathnode->fdw_outerpath = fdw_outerpath;
2105 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2106 pathnode->fdw_private = fdw_private;
2107
2108 return pathnode;
2109}
#define IS_SIMPLE_REL(rel)
Definition pathnodes.h:977

References Assert, RelOptInfo::consider_parallel, fb(), get_baserel_parampathinfo(), IS_SIMPLE_REL, makeNode, RelOptInfo::reltarget, and root.

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

1888{
1890
1891 pathnode->pathtype = T_FunctionScan;
1892 pathnode->parent = rel;
1893 pathnode->pathtarget = rel->reltarget;
1894 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1896 pathnode->parallel_aware = false;
1897 pathnode->parallel_safe = rel->consider_parallel;
1898 pathnode->parallel_workers = 0;
1899 pathnode->pathkeys = pathkeys;
1900
1901 cost_functionscan(pathnode, root, rel, pathnode->param_info);
1902
1903 return pathnode;
1904}
void cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1562

References RelOptInfo::consider_parallel, cost_functionscan(), fb(), get_baserel_parampathinfo(), makeNode, RelOptInfo::reltarget, and root.

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

1763{
1765 int input_disabled_nodes = 0;
1768
1769 Assert(subpath->parallel_safe);
1770 Assert(pathkeys);
1771
1772 /*
1773 * The subpath should guarantee that it is adequately ordered either by
1774 * adding an explicit sort node or by using presorted input. We cannot
1775 * add an explicit Sort node for the subpath in createplan.c on additional
1776 * pathkeys, because we can't guarantee the sort would be safe. For
1777 * example, expressions may be volatile or otherwise parallel unsafe.
1778 */
1779 if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
1780 elog(ERROR, "gather merge input not sufficiently sorted");
1781
1782 pathnode->path.pathtype = T_GatherMerge;
1783 pathnode->path.parent = rel;
1784 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1786 pathnode->path.parallel_aware = false;
1787
1788 pathnode->subpath = subpath;
1789 pathnode->num_workers = subpath->parallel_workers;
1790 pathnode->path.pathkeys = pathkeys;
1791 pathnode->path.pathtarget = target ? target : rel->reltarget;
1792
1793 input_disabled_nodes += subpath->disabled_nodes;
1794 input_startup_cost += subpath->startup_cost;
1795 input_total_cost += subpath->total_cost;
1796
1797 cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
1799 input_total_cost, rows);
1800
1801 return pathnode;
1802}
void cost_gather_merge(GatherMergePath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double *rows)
Definition costsize.c:469
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition pathkeys.c:343

References Assert, cost_gather_merge(), elog, ERROR, fb(), get_baserel_parampathinfo(), makeNode, pathkeys_contained_in(), RelOptInfo::reltarget, root, and subpath().

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

1814{
1816
1817 Assert(subpath->parallel_safe);
1818
1819 pathnode->path.pathtype = T_Gather;
1820 pathnode->path.parent = rel;
1821 pathnode->path.pathtarget = target;
1822 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1824 pathnode->path.parallel_aware = false;
1825 pathnode->path.parallel_safe = false;
1826 pathnode->path.parallel_workers = 0;
1827 pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1828
1829 pathnode->subpath = subpath;
1830 pathnode->num_workers = subpath->parallel_workers;
1831 pathnode->single_copy = false;
1832
1833 if (pathnode->num_workers == 0)
1834 {
1835 pathnode->path.pathkeys = subpath->pathkeys;
1836 pathnode->num_workers = 1;
1837 pathnode->single_copy = true;
1838 }
1839
1840 cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1841
1842 return pathnode;
1843}
void cost_gather(GatherPath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, double *rows)
Definition costsize.c:429

References Assert, cost_gather(), fb(), get_baserel_parampathinfo(), makeNode, NIL, root, and 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 2895 of file pathnode.c.

2901{
2903 PathTarget *target = rel->reltarget;
2904
2905 pathnode->path.pathtype = T_Group;
2906 pathnode->path.parent = rel;
2907 pathnode->path.pathtarget = target;
2908 /* For now, assume we are above any joins, so no parameterization */
2909 pathnode->path.param_info = NULL;
2910 pathnode->path.parallel_aware = false;
2911 pathnode->path.parallel_safe = rel->consider_parallel &&
2912 subpath->parallel_safe;
2913 pathnode->path.parallel_workers = subpath->parallel_workers;
2914 /* Group doesn't change sort ordering */
2915 pathnode->path.pathkeys = subpath->pathkeys;
2916
2917 pathnode->subpath = subpath;
2918
2919 pathnode->groupClause = groupClause;
2920 pathnode->qual = qual;
2921
2922 cost_group(&pathnode->path, root,
2923 list_length(groupClause),
2924 numGroups,
2925 qual,
2926 subpath->disabled_nodes,
2927 subpath->startup_cost, subpath->total_cost,
2928 subpath->rows);
2929
2930 /* add tlist eval cost for each output row */
2931 pathnode->path.startup_cost += target->cost.startup;
2932 pathnode->path.total_cost += target->cost.startup +
2933 target->cost.per_tuple * pathnode->path.rows;
2934
2935 return pathnode;
2936}
void cost_group(Path *path, PlannerInfo *root, int numGroupCols, double numGroups, List *quals, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition costsize.c:3300

References RelOptInfo::consider_parallel, PathTarget::cost, cost_group(), fb(), list_length(), makeNode, QualCost::per_tuple, RelOptInfo::reltarget, root, QualCost::startup, and subpath().

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

1613{
1615
1616 pathnode->path.pathtype = T_Result;
1617 pathnode->path.parent = rel;
1618 pathnode->path.pathtarget = target;
1619 pathnode->path.param_info = NULL; /* there are no other rels... */
1620 pathnode->path.parallel_aware = false;
1621 pathnode->path.parallel_safe = rel->consider_parallel;
1622 pathnode->path.parallel_workers = 0;
1623 pathnode->path.pathkeys = NIL;
1624 pathnode->quals = havingqual;
1625
1626 /*
1627 * We can't quite use cost_resultscan() because the quals we want to
1628 * account for are not baserestrict quals of the rel. Might as well just
1629 * hack it here.
1630 */
1631 pathnode->path.rows = 1;
1632 pathnode->path.startup_cost = target->cost.startup;
1633 pathnode->path.total_cost = target->cost.startup +
1634 cpu_tuple_cost + target->cost.per_tuple;
1635
1636 /*
1637 * Add cost of qual, if any --- but we ignore its selectivity, since our
1638 * rowcount estimate should be 1 no matter what the qual is.
1639 */
1640 if (havingqual)
1641 {
1643
1645 /* havingqual is evaluated once at startup */
1646 pathnode->path.startup_cost += qual_cost.startup + qual_cost.per_tuple;
1647 pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
1648 }
1649
1650 return pathnode;
1651}
double cpu_tuple_cost
Definition costsize.c:132
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition costsize.c:4898

References RelOptInfo::consider_parallel, PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, fb(), makeNode, NIL, QualCost::per_tuple, root, and QualCost::startup.

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

3093{
3095 PathTarget *target = rel->reltarget;
3096 ListCell *lc;
3097 bool is_first = true;
3098 bool is_first_sort = true;
3099
3100 /* The topmost generated Plan node will be an Agg */
3101 pathnode->path.pathtype = T_Agg;
3102 pathnode->path.parent = rel;
3103 pathnode->path.pathtarget = target;
3104 pathnode->path.param_info = subpath->param_info;
3105 pathnode->path.parallel_aware = false;
3106 pathnode->path.parallel_safe = rel->consider_parallel &&
3107 subpath->parallel_safe;
3108 pathnode->path.parallel_workers = subpath->parallel_workers;
3109 pathnode->subpath = subpath;
3110
3111 /*
3112 * Simplify callers by downgrading AGG_SORTED to AGG_PLAIN, and AGG_MIXED
3113 * to AGG_HASHED, here if possible.
3114 */
3115 if (aggstrategy == AGG_SORTED &&
3116 list_length(rollups) == 1 &&
3117 ((RollupData *) linitial(rollups))->groupClause == NIL)
3118 aggstrategy = AGG_PLAIN;
3119
3120 if (aggstrategy == AGG_MIXED &&
3121 list_length(rollups) == 1)
3122 aggstrategy = AGG_HASHED;
3123
3124 /*
3125 * Output will be in sorted order by group_pathkeys if, and only if, there
3126 * is a single rollup operation on a non-empty list of grouping
3127 * expressions.
3128 */
3129 if (aggstrategy == AGG_SORTED && list_length(rollups) == 1)
3130 pathnode->path.pathkeys = root->group_pathkeys;
3131 else
3132 pathnode->path.pathkeys = NIL;
3133
3134 pathnode->aggstrategy = aggstrategy;
3135 pathnode->rollups = rollups;
3136 pathnode->qual = having_qual;
3137 pathnode->transitionSpace = agg_costs ? agg_costs->transitionSpace : 0;
3138
3139 Assert(rollups != NIL);
3140 Assert(aggstrategy != AGG_PLAIN || list_length(rollups) == 1);
3141 Assert(aggstrategy != AGG_MIXED || list_length(rollups) > 1);
3142
3143 foreach(lc, rollups)
3144 {
3146 List *gsets = rollup->gsets;
3147 int numGroupCols = list_length(linitial(gsets));
3148
3149 /*
3150 * In AGG_SORTED or AGG_PLAIN mode, the first rollup takes the
3151 * (already-sorted) input, and following ones do their own sort.
3152 *
3153 * In AGG_HASHED mode, there is one rollup for each grouping set.
3154 *
3155 * In AGG_MIXED mode, the first rollups are hashed, the first
3156 * non-hashed one takes the (already-sorted) input, and following ones
3157 * do their own sort.
3158 */
3159 if (is_first)
3160 {
3161 cost_agg(&pathnode->path, root,
3162 aggstrategy,
3163 agg_costs,
3165 rollup->numGroups,
3167 subpath->disabled_nodes,
3168 subpath->startup_cost,
3169 subpath->total_cost,
3170 subpath->rows,
3171 subpath->pathtarget->width);
3172 is_first = false;
3173 if (!rollup->is_hashed)
3174 is_first_sort = false;
3175 }
3176 else
3177 {
3178 Path sort_path; /* dummy for result of cost_sort */
3179 Path agg_path; /* dummy for result of cost_agg */
3180
3181 if (rollup->is_hashed || is_first_sort)
3182 {
3183 /*
3184 * Account for cost of aggregation, but don't charge input
3185 * cost again
3186 */
3188 rollup->is_hashed ? AGG_HASHED : AGG_SORTED,
3189 agg_costs,
3191 rollup->numGroups,
3193 0, 0.0, 0.0,
3194 subpath->rows,
3195 subpath->pathtarget->width);
3196 if (!rollup->is_hashed)
3197 is_first_sort = false;
3198 }
3199 else
3200 {
3201 /* Account for cost of sort, but don't charge input cost again */
3203 0.0,
3204 subpath->rows,
3205 subpath->pathtarget->width,
3206 0.0,
3207 work_mem,
3208 -1.0);
3209
3210 /* Account for cost of aggregation */
3211
3213 AGG_SORTED,
3214 agg_costs,
3216 rollup->numGroups,
3218 sort_path.disabled_nodes,
3219 sort_path.startup_cost,
3220 sort_path.total_cost,
3221 sort_path.rows,
3222 subpath->pathtarget->width);
3223 }
3224
3225 pathnode->path.disabled_nodes += agg_path.disabled_nodes;
3226 pathnode->path.total_cost += agg_path.total_cost;
3227 pathnode->path.rows += agg_path.rows;
3228 }
3229 }
3230
3231 /* add tlist eval cost for each output row */
3232 pathnode->path.startup_cost += target->cost.startup;
3233 pathnode->path.total_cost += target->cost.startup +
3234 target->cost.per_tuple * pathnode->path.rows;
3235
3236 return pathnode;
3237}
void cost_sort(Path *path, PlannerInfo *root, List *pathkeys, int input_disabled_nodes, Cost input_cost, double tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition costsize.c:2200
int work_mem
Definition globals.c:131
@ AGG_HASHED
Definition nodes.h:366
@ AGG_MIXED
Definition nodes.h:367
@ AGG_PLAIN
Definition nodes.h:364

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, Assert, RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), cost_sort(), fb(), lfirst, linitial, list_length(), makeNode, NIL, QualCost::per_tuple, RelOptInfo::reltarget, root, QualCost::startup, subpath(), 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 2468 of file pathnode.c.

2479{
2481
2482 pathnode->jpath.path.pathtype = T_HashJoin;
2483 pathnode->jpath.path.parent = joinrel;
2484 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2485 pathnode->jpath.path.param_info =
2487 joinrel,
2488 outer_path,
2489 inner_path,
2490 extra->sjinfo,
2493 pathnode->jpath.path.parallel_aware =
2494 joinrel->consider_parallel && parallel_hash;
2495 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2496 outer_path->parallel_safe && inner_path->parallel_safe;
2497 /* This is a foolish way to estimate parallel_workers, but for now... */
2498 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2499
2500 /*
2501 * A hashjoin never has pathkeys, since its output ordering is
2502 * unpredictable due to possible batching. XXX If the inner relation is
2503 * small enough, we could instruct the executor that it must not batch,
2504 * and then we could assume that the output inherits the outer relation's
2505 * ordering, which might save a sort step. However there is considerable
2506 * downside if our estimate of the inner relation size is badly off. For
2507 * the moment we don't risk it. (Note also that if we wanted to take this
2508 * seriously, joinpath.c would have to consider many more paths for the
2509 * outer rel than it does now.)
2510 */
2511 pathnode->jpath.path.pathkeys = NIL;
2512 pathnode->jpath.jointype = jointype;
2513 pathnode->jpath.inner_unique = extra->inner_unique;
2514 pathnode->jpath.outerjoinpath = outer_path;
2515 pathnode->jpath.innerjoinpath = inner_path;
2516 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2517 pathnode->path_hashclauses = hashclauses;
2518 /* final_cost_hashjoin will fill in pathnode->num_batches */
2519
2520 final_cost_hashjoin(root, pathnode, workspace, extra);
2521
2522 return pathnode;
2523}
void final_cost_hashjoin(PlannerInfo *root, HashPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition costsize.c:4415
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:1807
SpecialJoinInfo * sjinfo
Definition pathnodes.h:3594

References RelOptInfo::consider_parallel, fb(), final_cost_hashjoin(), get_joinrel_parampathinfo(), JoinPathExtraData::inner_unique, makeNode, NIL, RelOptInfo::reltarget, root, 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 2802 of file pathnode.c.

2808{
2810 SortPath *pathnode = &sort->spath;
2811
2813 pathnode->path.parent = rel;
2814 /* Sort doesn't project, so use source path's pathtarget */
2815 pathnode->path.pathtarget = subpath->pathtarget;
2816 pathnode->path.param_info = subpath->param_info;
2817 pathnode->path.parallel_aware = false;
2818 pathnode->path.parallel_safe = rel->consider_parallel &&
2819 subpath->parallel_safe;
2820 pathnode->path.parallel_workers = subpath->parallel_workers;
2821 pathnode->path.pathkeys = pathkeys;
2822
2823 pathnode->subpath = subpath;
2824
2826 root, pathkeys, presorted_keys,
2827 subpath->disabled_nodes,
2828 subpath->startup_cost,
2829 subpath->total_cost,
2830 subpath->rows,
2831 subpath->pathtarget->width,
2832 0.0, /* XXX comparison_cost shouldn't be 0? */
2833 work_mem, limit_tuples);
2834
2835 sort->nPresortedCols = presorted_keys;
2836
2837 return sort;
2838}
Datum sort(PG_FUNCTION_ARGS)
Definition _int_op.c:198
void cost_incremental_sort(Path *path, PlannerInfo *root, List *pathkeys, int presorted_keys, int input_disabled_nodes, 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:2052
NodeTag pathtype
Definition pathnodes.h:1957
Path path
Definition pathnodes.h:2523

References RelOptInfo::consider_parallel, cost_incremental_sort(), fb(), makeNode, SortPath::path, Path::pathtype, root, sort(), subpath(), and work_mem.

Referenced by build_setop_child_paths(), create_final_unique_paths(), create_one_window_path(), create_ordered_paths(), create_partial_unique_paths(), gather_grouping_paths(), generate_grouped_paths(), generate_useful_gather_paths(), and make_ordered_path().

◆ create_index_path()

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

Definition at line 1047 of file pathnode.c.

1058{
1060 RelOptInfo *rel = index->rel;
1061
1062 pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
1063 pathnode->path.parent = rel;
1064 pathnode->path.pathtarget = rel->reltarget;
1065 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1067 pathnode->path.parallel_aware = false;
1068 pathnode->path.parallel_safe = rel->consider_parallel;
1069 pathnode->path.parallel_workers = 0;
1070 pathnode->path.pathkeys = pathkeys;
1071
1072 pathnode->indexinfo = index;
1073 pathnode->indexclauses = indexclauses;
1074 pathnode->indexorderbys = indexorderbys;
1075 pathnode->indexorderbycols = indexorderbycols;
1076 pathnode->indexscandir = indexscandir;
1077
1079
1080 return pathnode;
1081}
void cost_index(IndexPath *path, PlannerInfo *root, double loop_count, bool partial_path)
Definition costsize.c:544
Definition type.h:96

References RelOptInfo::consider_parallel, cost_index(), fb(), get_baserel_parampathinfo(), makeNode, RelOptInfo::reltarget, and root.

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

3744{
3746
3747 pathnode->path.pathtype = T_Limit;
3748 pathnode->path.parent = rel;
3749 /* Limit doesn't project, so use source path's pathtarget */
3750 pathnode->path.pathtarget = subpath->pathtarget;
3751 /* For now, assume we are above any joins, so no parameterization */
3752 pathnode->path.param_info = NULL;
3753 pathnode->path.parallel_aware = false;
3754 pathnode->path.parallel_safe = rel->consider_parallel &&
3755 subpath->parallel_safe;
3756 pathnode->path.parallel_workers = subpath->parallel_workers;
3757 pathnode->path.rows = subpath->rows;
3758 pathnode->path.disabled_nodes = subpath->disabled_nodes;
3759 pathnode->path.startup_cost = subpath->startup_cost;
3760 pathnode->path.total_cost = subpath->total_cost;
3761 pathnode->path.pathkeys = subpath->pathkeys;
3762 pathnode->subpath = subpath;
3763 pathnode->limitOffset = limitOffset;
3764 pathnode->limitCount = limitCount;
3765 pathnode->limitOption = limitOption;
3766
3767 /*
3768 * Adjust the output rows count and costs according to the offset/limit.
3769 */
3771 &pathnode->path.startup_cost,
3772 &pathnode->path.total_cost,
3773 offset_est, count_est);
3774
3775 return pathnode;
3776}
void adjust_limit_rows_costs(double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
Definition pathnode.c:3795

References adjust_limit_rows_costs(), RelOptInfo::consider_parallel, fb(), makeNode, and subpath().

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

◆ create_lockrows_path()

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

Definition at line 3577 of file pathnode.c.

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

References cpu_tuple_cost, fb(), makeNode, NIL, RelOptInfo::rows, and subpath().

Referenced by grouping_planner().

◆ create_material_path()

MaterialPath * create_material_path ( RelOptInfo rel,
Path subpath,
bool  enabled 
)

Definition at line 1659 of file pathnode.c.

1660{
1662
1663 Assert(subpath->parent == rel);
1664
1665 pathnode->path.pathtype = T_Material;
1666 pathnode->path.parent = rel;
1667 pathnode->path.pathtarget = rel->reltarget;
1668 pathnode->path.param_info = subpath->param_info;
1669 pathnode->path.parallel_aware = false;
1670 pathnode->path.parallel_safe = rel->consider_parallel &&
1671 subpath->parallel_safe;
1672 pathnode->path.parallel_workers = subpath->parallel_workers;
1673 pathnode->path.pathkeys = subpath->pathkeys;
1674
1675 pathnode->subpath = subpath;
1676
1677 cost_material(&pathnode->path,
1678 enabled,
1679 subpath->disabled_nodes,
1680 subpath->startup_cost,
1681 subpath->total_cost,
1682 subpath->rows,
1683 subpath->pathtarget->width);
1684
1685 return pathnode;
1686}
void cost_material(Path *path, bool enabled, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition costsize.c:2582

References Assert, RelOptInfo::consider_parallel, cost_material(), fb(), makeNode, RelOptInfo::reltarget, and subpath().

Referenced by consider_parallel_nestloop(), 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,
Cardinality  est_calls 
)

Definition at line 1693 of file pathnode.c.

1696{
1698
1699 Assert(subpath->parent == rel);
1700
1701 pathnode->path.pathtype = T_Memoize;
1702 pathnode->path.parent = rel;
1703 pathnode->path.pathtarget = rel->reltarget;
1704 pathnode->path.param_info = subpath->param_info;
1705 pathnode->path.parallel_aware = false;
1706 pathnode->path.parallel_safe = rel->consider_parallel &&
1707 subpath->parallel_safe;
1708 pathnode->path.parallel_workers = subpath->parallel_workers;
1709 pathnode->path.pathkeys = subpath->pathkeys;
1710
1711 pathnode->subpath = subpath;
1712 pathnode->hash_operators = hash_operators;
1713 pathnode->param_exprs = param_exprs;
1714 pathnode->singlerow = singlerow;
1715 pathnode->binary_mode = binary_mode;
1716
1717 /*
1718 * For now we set est_entries to 0. cost_memoize_rescan() does all the
1719 * hard work to determine how many cache entries there are likely to be,
1720 * so it seems best to leave it up to that function to fill this field in.
1721 * If left at 0, the executor will make a guess at a good value.
1722 */
1723 pathnode->est_entries = 0;
1724
1725 pathnode->est_calls = clamp_row_est(est_calls);
1726
1727 /* These will also be set later in cost_memoize_rescan() */
1728 pathnode->est_unique_keys = 0.0;
1729 pathnode->est_hit_ratio = 0.0;
1730
1731 /*
1732 * We should not be asked to generate this path type when memoization is
1733 * disabled, so set our count of disabled nodes equal to the subpath's
1734 * count.
1735 *
1736 * It would be nice to also Assert that memoization is enabled, but the
1737 * value of enable_memoize is not controlling: what we would need to check
1738 * is that the JoinPathExtraData's pgs_mask included PGS_NESTLOOP_MEMOIZE.
1739 */
1740 pathnode->path.disabled_nodes = subpath->disabled_nodes;
1741
1742 /*
1743 * Add a small additional charge for caching the first entry. All the
1744 * harder calculations for rescans are performed in cost_memoize_rescan().
1745 */
1746 pathnode->path.startup_cost = subpath->startup_cost + cpu_tuple_cost;
1747 pathnode->path.total_cost = subpath->total_cost + cpu_tuple_cost;
1748 pathnode->path.rows = subpath->rows;
1749
1750 return pathnode;
1751}

References Assert, clamp_row_est(), RelOptInfo::consider_parallel, cpu_tuple_cost, fb(), makeNode, RelOptInfo::reltarget, and subpath().

Referenced by get_memoize_path(), and reparameterize_path().

◆ create_merge_append_path()

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

Definition at line 1471 of file pathnode.c.

1477{
1482 ListCell *l;
1483
1484 /*
1485 * We don't currently support parameterized MergeAppend paths, as
1486 * explained in the comments for generate_orderedappend_paths.
1487 */
1489
1490 pathnode->child_append_relid_sets = child_append_relid_sets;
1491 pathnode->path.pathtype = T_MergeAppend;
1492 pathnode->path.parent = rel;
1493 pathnode->path.pathtarget = rel->reltarget;
1494 pathnode->path.param_info = NULL;
1495 pathnode->path.parallel_aware = false;
1496 pathnode->path.parallel_safe = rel->consider_parallel;
1497 pathnode->path.parallel_workers = 0;
1498 pathnode->path.pathkeys = pathkeys;
1499 pathnode->subpaths = subpaths;
1500
1501 /*
1502 * Apply query-wide LIMIT if known and path is for sole base relation.
1503 * (Handling this at this low level is a bit klugy.)
1504 */
1505 if (bms_equal(rel->relids, root->all_query_rels))
1506 pathnode->limit_tuples = root->limit_tuples;
1507 else
1508 pathnode->limit_tuples = -1.0;
1509
1510 /*
1511 * Add up the sizes and costs of the input paths.
1512 */
1513 pathnode->path.rows = 0;
1516 input_total_cost = 0;
1517 foreach(l, subpaths)
1518 {
1519 Path *subpath = (Path *) lfirst(l);
1520 int presorted_keys;
1521 Path sort_path; /* dummy for result of
1522 * cost_sort/cost_incremental_sort */
1523
1524 /* All child paths should be unparameterized */
1526
1527 pathnode->path.rows += subpath->rows;
1528 pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1529 subpath->parallel_safe;
1530
1531 if (!pathkeys_count_contained_in(pathkeys, subpath->pathkeys,
1532 &presorted_keys))
1533 {
1534 /*
1535 * We'll need to insert a Sort node, so include costs for that. We
1536 * choose to use incremental sort if it is enabled and there are
1537 * presorted keys; otherwise we use full sort.
1538 *
1539 * We can use the parent's LIMIT if any, since we certainly won't
1540 * pull more than that many tuples from any child.
1541 */
1542 if (enable_incremental_sort && presorted_keys > 0)
1543 {
1545 root,
1546 pathkeys,
1547 presorted_keys,
1548 subpath->disabled_nodes,
1549 subpath->startup_cost,
1550 subpath->total_cost,
1551 subpath->rows,
1552 subpath->pathtarget->width,
1553 0.0,
1554 work_mem,
1555 pathnode->limit_tuples);
1556 }
1557 else
1558 {
1560 root,
1561 pathkeys,
1562 subpath->disabled_nodes,
1563 subpath->total_cost,
1564 subpath->rows,
1565 subpath->pathtarget->width,
1566 0.0,
1567 work_mem,
1568 pathnode->limit_tuples);
1569 }
1570
1571 subpath = &sort_path;
1572 }
1573
1574 input_disabled_nodes += subpath->disabled_nodes;
1575 input_startup_cost += subpath->startup_cost;
1576 input_total_cost += subpath->total_cost;
1577 }
1578
1579 /*
1580 * Now we can compute total costs of the MergeAppend. If there's exactly
1581 * one child path and its parallel awareness matches that of the
1582 * MergeAppend, then the MergeAppend is a no-op and will be discarded
1583 * later (in setrefs.c); otherwise we do the normal cost calculation.
1584 */
1585 if (list_length(subpaths) == 1 &&
1586 ((Path *) linitial(subpaths))->parallel_aware ==
1587 pathnode->path.parallel_aware)
1588 {
1589 pathnode->path.disabled_nodes = input_disabled_nodes;
1590 pathnode->path.startup_cost = input_startup_cost;
1591 pathnode->path.total_cost = input_total_cost;
1592 }
1593 else
1595 pathkeys, list_length(subpaths),
1598 pathnode->path.rows);
1599
1600 return pathnode;
1601}
void cost_merge_append(Path *path, PlannerInfo *root, List *pathkeys, int n_streams, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double tuples)
Definition costsize.c:2524
bool enable_incremental_sort
Definition costsize.c:151
bool pathkeys_count_contained_in(List *keys1, List *keys2, int *n_common)
Definition pathkeys.c:558

References Assert, bms_equal(), bms_is_empty, RelOptInfo::consider_parallel, cost_incremental_sort(), cost_merge_append(), cost_sort(), enable_incremental_sort, fb(), RelOptInfo::lateral_relids, lfirst, linitial, list_length(), makeNode, PATH_REQ_OUTER, pathkeys_count_contained_in(), RelOptInfo::relids, RelOptInfo::reltarget, root, subpath(), and work_mem.

Referenced by generate_orderedappend_paths(), and generate_union_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,
int  outer_presorted_keys 
)

Definition at line 2400 of file pathnode.c.

2414{
2416
2417 pathnode->jpath.path.pathtype = T_MergeJoin;
2418 pathnode->jpath.path.parent = joinrel;
2419 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2420 pathnode->jpath.path.param_info =
2422 joinrel,
2423 outer_path,
2424 inner_path,
2425 extra->sjinfo,
2428 pathnode->jpath.path.parallel_aware = false;
2429 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2430 outer_path->parallel_safe && inner_path->parallel_safe;
2431 /* This is a foolish way to estimate parallel_workers, but for now... */
2432 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2433 pathnode->jpath.path.pathkeys = pathkeys;
2434 pathnode->jpath.jointype = jointype;
2435 pathnode->jpath.inner_unique = extra->inner_unique;
2436 pathnode->jpath.outerjoinpath = outer_path;
2437 pathnode->jpath.innerjoinpath = inner_path;
2438 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2439 pathnode->path_mergeclauses = mergeclauses;
2440 pathnode->outersortkeys = outersortkeys;
2441 pathnode->innersortkeys = innersortkeys;
2442 pathnode->outer_presorted_keys = outer_presorted_keys;
2443 /* pathnode->skip_mark_restore will be set by final_cost_mergejoin */
2444 /* pathnode->materialize_inner will be set by final_cost_mergejoin */
2445
2446 final_cost_mergejoin(root, pathnode, workspace, extra);
2447
2448 return pathnode;
2449}
void final_cost_mergejoin(PlannerInfo *root, MergePath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition costsize.c:3954

References RelOptInfo::consider_parallel, fb(), final_cost_mergejoin(), get_joinrel_parampathinfo(), JoinPathExtraData::inner_unique, makeNode, RelOptInfo::reltarget, root, 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 3249 of file pathnode.c.

3254{
3258 ListCell *lc;
3259
3260 /* The topmost generated Plan node will be a Result */
3261 pathnode->path.pathtype = T_Result;
3262 pathnode->path.parent = rel;
3263 pathnode->path.pathtarget = target;
3264 /* For now, assume we are above any joins, so no parameterization */
3265 pathnode->path.param_info = NULL;
3266 pathnode->path.parallel_aware = false;
3267 pathnode->path.parallel_safe = true; /* might change below */
3268 pathnode->path.parallel_workers = 0;
3269 /* Result is one unordered row */
3270 pathnode->path.rows = 1;
3271 pathnode->path.pathkeys = NIL;
3272
3273 pathnode->mmaggregates = mmaggregates;
3274 pathnode->quals = quals;
3275
3276 /* Calculate cost of all the initplans, and check parallel safety */
3277 initplan_cost = 0;
3278 foreach(lc, mmaggregates)
3279 {
3281
3283 initplan_cost += mminfo->pathcost;
3284 if (!mminfo->path->parallel_safe)
3285 pathnode->path.parallel_safe = false;
3286 }
3287
3288 /* add tlist eval cost for each output row, plus cpu_tuple_cost */
3289 pathnode->path.disabled_nodes = initplan_disabled_nodes;
3290 pathnode->path.startup_cost = initplan_cost + target->cost.startup;
3291 pathnode->path.total_cost = initplan_cost + target->cost.startup +
3292 target->cost.per_tuple + cpu_tuple_cost;
3293
3294 /*
3295 * Add cost of qual, if any --- but we ignore its selectivity, since our
3296 * rowcount estimate should be 1 no matter what the qual is.
3297 */
3298 if (quals)
3299 {
3301
3302 cost_qual_eval(&qual_cost, quals, root);
3303 pathnode->path.startup_cost += qual_cost.startup;
3304 pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
3305 }
3306
3307 /*
3308 * If the initplans were all parallel-safe, also check safety of the
3309 * target and quals. (The Result node itself isn't parallelizable, but if
3310 * we are in a subquery then it can be useful for the outer query to know
3311 * that this one is parallel-safe.)
3312 */
3313 if (pathnode->path.parallel_safe)
3314 pathnode->path.parallel_safe =
3315 is_parallel_safe(root, (Node *) target->exprs) &&
3316 is_parallel_safe(root, (Node *) quals);
3317
3318 return pathnode;
3319}
int disabled_nodes
Definition pathnodes.h:1992

References PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, Path::disabled_nodes, PathTarget::exprs, fb(), is_parallel_safe(), lfirst, makeNode, NIL, MinMaxAggInfo::path, QualCost::per_tuple, root, and QualCost::startup.

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,
List resultRelations,
List updateColnosLists,
List withCheckOptionLists,
List returningLists,
List rowMarks,
OnConflictExpr onconflict,
List mergeActionLists,
List mergeJoinConditions,
int  epqParam 
)

Definition at line 3639 of file pathnode.c.

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

References Assert, CMD_MERGE, CMD_UPDATE, fb(), list_length(), makeNode, NIL, RelOptInfo::reltarget, subpath(), and PathTarget::width.

Referenced by grouping_planner().

◆ create_namedtuplestorescan_path()

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

Definition at line 1990 of file pathnode.c.

1992{
1994
1995 pathnode->pathtype = T_NamedTuplestoreScan;
1996 pathnode->parent = rel;
1997 pathnode->pathtarget = rel->reltarget;
1998 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2000 pathnode->parallel_aware = false;
2001 pathnode->parallel_safe = rel->consider_parallel;
2002 pathnode->parallel_workers = 0;
2003 pathnode->pathkeys = NIL; /* result is always unordered */
2004
2005 cost_namedtuplestorescan(pathnode, root, rel, pathnode->param_info);
2006
2007 return pathnode;
2008}
void cost_namedtuplestorescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1790

References RelOptInfo::consider_parallel, cost_namedtuplestorescan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

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

2313{
2316 Relids outerrelids;
2317
2318 /*
2319 * Paths are parameterized by top-level parents, so run parameterization
2320 * tests on the parent relids.
2321 */
2322 if (outer_path->parent->top_parent_relids)
2323 outerrelids = outer_path->parent->top_parent_relids;
2324 else
2325 outerrelids = outer_path->parent->relids;
2326
2327 /*
2328 * If the inner path is parameterized by the outer, we must drop any
2329 * restrict_clauses that are due to be moved into the inner path. We have
2330 * to do this now, rather than postpone the work till createplan time,
2331 * because the restrict_clauses list can affect the size and cost
2332 * estimates for this path. We detect such clauses by checking for serial
2333 * number match to clauses already enforced in the inner path.
2334 */
2335 if (bms_overlap(inner_req_outer, outerrelids))
2336 {
2338 List *jclauses = NIL;
2339 ListCell *lc;
2340
2341 foreach(lc, restrict_clauses)
2342 {
2343 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2344
2346 jclauses = lappend(jclauses, rinfo);
2347 }
2349 }
2350
2351 pathnode->jpath.path.pathtype = T_NestLoop;
2352 pathnode->jpath.path.parent = joinrel;
2353 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2354 pathnode->jpath.path.param_info =
2356 joinrel,
2357 outer_path,
2358 inner_path,
2359 extra->sjinfo,
2362 pathnode->jpath.path.parallel_aware = false;
2363 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2364 outer_path->parallel_safe && inner_path->parallel_safe;
2365 /* This is a foolish way to estimate parallel_workers, but for now... */
2366 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2367 pathnode->jpath.path.pathkeys = pathkeys;
2368 pathnode->jpath.jointype = jointype;
2369 pathnode->jpath.inner_unique = extra->inner_unique;
2370 pathnode->jpath.outerjoinpath = outer_path;
2371 pathnode->jpath.innerjoinpath = inner_path;
2372 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2373
2374 final_cost_nestloop(root, pathnode, workspace, extra);
2375
2376 return pathnode;
2377}
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
void final_cost_nestloop(PlannerInfo *root, NestPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition costsize.c:3454
List * lappend(List *list, void *datum)
Definition list.c:339
Bitmapset * get_param_path_clause_serials(Path *path)
Definition relnode.c:2058

References bms_is_member(), bms_overlap(), RelOptInfo::consider_parallel, fb(), final_cost_nestloop(), get_joinrel_parampathinfo(), get_param_path_clause_serials(), JoinPathExtraData::inner_unique, lappend(), lfirst, makeNode, NIL, PATH_REQ_OUTER, RelOptInfo::reltarget, RestrictInfo::rinfo_serial, root, 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 2534 of file pathnode.c.

2538{
2541
2542 /*
2543 * We mustn't put a ProjectionPath directly above another; it's useless
2544 * and will confuse create_projection_plan. Rather than making sure all
2545 * callers handle that, let's implement it here, by stripping off any
2546 * ProjectionPath in what we're given. Given this rule, there won't be
2547 * more than one.
2548 */
2550 {
2552
2553 Assert(subpp->path.parent == rel);
2554 subpath = subpp->subpath;
2556 }
2557
2558 pathnode->path.pathtype = T_Result;
2559 pathnode->path.parent = rel;
2560 pathnode->path.pathtarget = target;
2561 pathnode->path.param_info = subpath->param_info;
2562 pathnode->path.parallel_aware = false;
2563 pathnode->path.parallel_safe = rel->consider_parallel &&
2564 subpath->parallel_safe &&
2565 is_parallel_safe(root, (Node *) target->exprs);
2566 pathnode->path.parallel_workers = subpath->parallel_workers;
2567 /* Projection does not change the sort order */
2568 pathnode->path.pathkeys = subpath->pathkeys;
2569
2570 pathnode->subpath = subpath;
2571
2572 /*
2573 * We might not need a separate Result node. If the input plan node type
2574 * can project, we can just tell it to project something else. Or, if it
2575 * can't project but the desired target has the same expression list as
2576 * what the input will produce anyway, we can still give it the desired
2577 * tlist (possibly changing its ressortgroupref labels, but nothing else).
2578 * Note: in the latter case, create_projection_plan has to recheck our
2579 * conclusion; see comments therein.
2580 */
2581 oldtarget = subpath->pathtarget;
2583 equal(oldtarget->exprs, target->exprs))
2584 {
2585 /* No separate Result node needed */
2586 pathnode->dummypp = true;
2587
2588 /*
2589 * Set cost of plan as subpath's cost, adjusted for tlist replacement.
2590 */
2591 pathnode->path.rows = subpath->rows;
2592 pathnode->path.disabled_nodes = subpath->disabled_nodes;
2593 pathnode->path.startup_cost = subpath->startup_cost +
2594 (target->cost.startup - oldtarget->cost.startup);
2595 pathnode->path.total_cost = subpath->total_cost +
2596 (target->cost.startup - oldtarget->cost.startup) +
2597 (target->cost.per_tuple - oldtarget->cost.per_tuple) * subpath->rows;
2598 }
2599 else
2600 {
2601 /* We really do need the Result node */
2602 pathnode->dummypp = false;
2603
2604 /*
2605 * The Result node's cost is cpu_tuple_cost per row, plus the cost of
2606 * evaluating the tlist. There is no qual to worry about.
2607 */
2608 pathnode->path.rows = subpath->rows;
2609 pathnode->path.disabled_nodes = subpath->disabled_nodes;
2610 pathnode->path.startup_cost = subpath->startup_cost +
2611 target->cost.startup;
2612 pathnode->path.total_cost = subpath->total_cost +
2613 target->cost.startup +
2614 (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows;
2615 }
2616
2617 return pathnode;
2618}
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223

References Assert, RelOptInfo::consider_parallel, PathTarget::cost, cpu_tuple_cost, equal(), PathTarget::exprs, fb(), is_parallel_safe(), is_projection_capable_path(), IsA, makeNode, QualCost::per_tuple, root, QualCost::startup, and subpath().

Referenced by add_paths_with_pathkeys_for_rel(), adjust_paths_for_srfs(), apply_projection_to_path(), apply_scanjoin_target_to_paths(), create_final_unique_paths(), create_partial_grouping_paths(), create_partial_unique_paths(), generate_grouped_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 3532 of file pathnode.c.

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

References RelOptInfo::consider_parallel, cost_recursive_union(), fb(), makeNode, NIL, Path::parallel_safe, and Path::parallel_workers.

Referenced by generate_recursion_path().

◆ create_resultscan_path()

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

Definition at line 2016 of file pathnode.c.

2018{
2020
2021 pathnode->pathtype = T_Result;
2022 pathnode->parent = rel;
2023 pathnode->pathtarget = rel->reltarget;
2024 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2026 pathnode->parallel_aware = false;
2027 pathnode->parallel_safe = rel->consider_parallel;
2028 pathnode->parallel_workers = 0;
2029 pathnode->pathkeys = NIL; /* result is always unordered */
2030
2031 cost_resultscan(pathnode, root, rel, pathnode->param_info);
2032
2033 return pathnode;
2034}
void cost_resultscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1832

References RelOptInfo::consider_parallel, cost_resultscan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

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

1007{
1009
1010 pathnode->pathtype = T_SampleScan;
1011 pathnode->parent = rel;
1012 pathnode->pathtarget = rel->reltarget;
1013 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1015 pathnode->parallel_aware = false;
1016 pathnode->parallel_safe = rel->consider_parallel;
1017 pathnode->parallel_workers = 0;
1018 pathnode->pathkeys = NIL; /* samplescan has unordered result */
1019
1020 cost_samplescan(pathnode, root, rel, pathnode->param_info);
1021
1022 return pathnode;
1023}
void cost_samplescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:348

References RelOptInfo::consider_parallel, cost_samplescan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

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

983{
985
986 pathnode->pathtype = T_SeqScan;
987 pathnode->parent = rel;
988 pathnode->pathtarget = rel->reltarget;
989 pathnode->param_info = get_baserel_parampathinfo(root, rel,
991 pathnode->parallel_aware = (parallel_workers > 0);
992 pathnode->parallel_safe = rel->consider_parallel;
993 pathnode->parallel_workers = parallel_workers;
994 pathnode->pathkeys = NIL; /* seqscan has unordered result */
995
996 cost_seqscan(pathnode, root, rel, pathnode->param_info);
997
998 return pathnode;
999}
void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:269

References RelOptInfo::consider_parallel, cost_seqscan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

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

2736{
2738 double tlist_rows;
2739 ListCell *lc;
2740
2741 pathnode->path.pathtype = T_ProjectSet;
2742 pathnode->path.parent = rel;
2743 pathnode->path.pathtarget = target;
2744 /* For now, assume we are above any joins, so no parameterization */
2745 pathnode->path.param_info = NULL;
2746 pathnode->path.parallel_aware = false;
2747 pathnode->path.parallel_safe = rel->consider_parallel &&
2748 subpath->parallel_safe &&
2749 is_parallel_safe(root, (Node *) target->exprs);
2750 pathnode->path.parallel_workers = subpath->parallel_workers;
2751 /* Projection does not change the sort order XXX? */
2752 pathnode->path.pathkeys = subpath->pathkeys;
2753
2754 pathnode->subpath = subpath;
2755
2756 /*
2757 * Estimate number of rows produced by SRFs for each row of input; if
2758 * there's more than one in this node, use the maximum.
2759 */
2760 tlist_rows = 1;
2761 foreach(lc, target->exprs)
2762 {
2763 Node *node = (Node *) lfirst(lc);
2764 double itemrows;
2765
2767 if (tlist_rows < itemrows)
2769 }
2770
2771 /*
2772 * In addition to the cost of evaluating the tlist, charge cpu_tuple_cost
2773 * per input row, and half of cpu_tuple_cost for each added output row.
2774 * This is slightly bizarre maybe, but it's what 9.6 did; we may revisit
2775 * this estimate later.
2776 */
2777 pathnode->path.disabled_nodes = subpath->disabled_nodes;
2778 pathnode->path.rows = subpath->rows * tlist_rows;
2779 pathnode->path.startup_cost = subpath->startup_cost +
2780 target->cost.startup;
2781 pathnode->path.total_cost = subpath->total_cost +
2782 target->cost.startup +
2783 (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows +
2784 (pathnode->path.rows - subpath->rows) * cpu_tuple_cost / 2;
2785
2786 return pathnode;
2787}
double expression_returns_set_rows(PlannerInfo *root, Node *clause)
Definition clauses.c:298

References RelOptInfo::consider_parallel, PathTarget::cost, cpu_tuple_cost, expression_returns_set_rows(), PathTarget::exprs, fb(), is_parallel_safe(), lfirst, makeNode, QualCost::per_tuple, root, QualCost::startup, and subpath().

Referenced by adjust_paths_for_srfs().

◆ create_setop_path()

SetOpPath * create_setop_path ( PlannerInfo root,
RelOptInfo rel,
Path leftpath,
Path rightpath,
SetOpCmd  cmd,
SetOpStrategy  strategy,
List groupList,
double  numGroups,
double  outputRows 
)

Definition at line 3413 of file pathnode.c.

3422{
3424
3425 pathnode->path.pathtype = T_SetOp;
3426 pathnode->path.parent = rel;
3427 pathnode->path.pathtarget = rel->reltarget;
3428 /* For now, assume we are above any joins, so no parameterization */
3429 pathnode->path.param_info = NULL;
3430 pathnode->path.parallel_aware = false;
3431 pathnode->path.parallel_safe = rel->consider_parallel &&
3432 leftpath->parallel_safe && rightpath->parallel_safe;
3433 pathnode->path.parallel_workers =
3434 leftpath->parallel_workers + rightpath->parallel_workers;
3435 /* SetOp preserves the input sort order if in sort mode */
3436 pathnode->path.pathkeys =
3437 (strategy == SETOP_SORTED) ? leftpath->pathkeys : NIL;
3438
3439 pathnode->leftpath = leftpath;
3440 pathnode->rightpath = rightpath;
3441 pathnode->cmd = cmd;
3442 pathnode->strategy = strategy;
3443 pathnode->groupList = groupList;
3444 pathnode->numGroups = numGroups;
3445
3446 /*
3447 * Compute cost estimates. As things stand, we end up with the same total
3448 * cost in this node for sort and hash methods, but different startup
3449 * costs. This could be refined perhaps, but it'll do for now.
3450 */
3451 pathnode->path.disabled_nodes =
3452 leftpath->disabled_nodes + rightpath->disabled_nodes;
3453 if (strategy == SETOP_SORTED)
3454 {
3455 /*
3456 * In sorted mode, we can emit output incrementally. Charge one
3457 * cpu_operator_cost per comparison per input tuple. Like cost_group,
3458 * we assume all columns get compared at most of the tuples.
3459 */
3460 pathnode->path.startup_cost =
3461 leftpath->startup_cost + rightpath->startup_cost;
3462 pathnode->path.total_cost =
3463 leftpath->total_cost + rightpath->total_cost +
3464 cpu_operator_cost * (leftpath->rows + rightpath->rows) * list_length(groupList);
3465
3466 /*
3467 * Also charge a small amount per extracted tuple. Like cost_sort,
3468 * charge only operator cost not cpu_tuple_cost, since SetOp does no
3469 * qual-checking or projection.
3470 */
3471 pathnode->path.total_cost += cpu_operator_cost * outputRows;
3472 }
3473 else
3474 {
3476
3477 /*
3478 * In hashed mode, we must read all the input before we can emit
3479 * anything. Also charge comparison costs to represent the cost of
3480 * hash table lookups.
3481 */
3482 pathnode->path.startup_cost =
3483 leftpath->total_cost + rightpath->total_cost +
3484 cpu_operator_cost * (leftpath->rows + rightpath->rows) * list_length(groupList);
3485 pathnode->path.total_cost = pathnode->path.startup_cost;
3486
3487 /*
3488 * Also charge a small amount per extracted tuple. Like cost_sort,
3489 * charge only operator cost not cpu_tuple_cost, since SetOp does no
3490 * qual-checking or projection.
3491 */
3492 pathnode->path.total_cost += cpu_operator_cost * outputRows;
3493
3494 /*
3495 * Mark the path as disabled if enable_hashagg is off. While this
3496 * isn't exactly a HashAgg node, it seems close enough to justify
3497 * letting that switch control it.
3498 */
3499 if (!enable_hashagg)
3500 pathnode->path.disabled_nodes++;
3501
3502 /*
3503 * Also disable if it doesn't look like the hashtable will fit into
3504 * hash_mem. (Note: reject on equality, to ensure that an estimate of
3505 * SIZE_MAX disables hashing regardless of the hash_mem limit.)
3506 */
3508 leftpath->pathtarget->width);
3510 pathnode->path.disabled_nodes++;
3511 }
3512 pathnode->path.rows = outputRows;
3513
3514 return pathnode;
3515}
size_t Size
Definition c.h:619
double cpu_operator_cost
Definition costsize.c:134
bool enable_hashagg
Definition costsize.c:152
size_t get_hash_memory_limit(void)
Definition nodeHash.c:3621
Size EstimateSetOpHashTableSpace(double nentries, Size tupleWidth)
Definition nodeSetOp.c:115
@ SETOP_SORTED
Definition nodes.h:416

References RelOptInfo::consider_parallel, cpu_operator_cost, Path::disabled_nodes, enable_hashagg, EstimateSetOpHashTableSpace(), fb(), get_hash_memory_limit(), list_length(), makeNode, NIL, Path::parallel_safe, Path::parallel_workers, Path::pathkeys, RelOptInfo::reltarget, Path::rows, SETOP_SORTED, Path::startup_cost, 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 2851 of file pathnode.c.

2856{
2858
2859 pathnode->path.pathtype = T_Sort;
2860 pathnode->path.parent = rel;
2861 /* Sort doesn't project, so use source path's pathtarget */
2862 pathnode->path.pathtarget = subpath->pathtarget;
2863 pathnode->path.param_info = subpath->param_info;
2864 pathnode->path.parallel_aware = false;
2865 pathnode->path.parallel_safe = rel->consider_parallel &&
2866 subpath->parallel_safe;
2867 pathnode->path.parallel_workers = subpath->parallel_workers;
2868 pathnode->path.pathkeys = pathkeys;
2869
2870 pathnode->subpath = subpath;
2871
2872 cost_sort(&pathnode->path, root, pathkeys,
2873 subpath->disabled_nodes,
2874 subpath->total_cost,
2875 subpath->rows,
2876 subpath->pathtarget->width,
2877 0.0, /* XXX comparison_cost shouldn't be 0? */
2878 work_mem, limit_tuples);
2879
2880 return pathnode;
2881}

References RelOptInfo::consider_parallel, cost_sort(), fb(), makeNode, root, subpath(), and work_mem.

Referenced by add_paths_with_pathkeys_for_rel(), build_setop_child_paths(), create_final_unique_paths(), create_one_window_path(), create_ordered_paths(), create_partial_unique_paths(), gather_grouping_paths(), generate_grouped_paths(), generate_nonunion_paths(), generate_union_paths(), generate_useful_gather_paths(), and make_ordered_path().

◆ create_subqueryscan_path()

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

Definition at line 1856 of file pathnode.c.

1859{
1861
1862 pathnode->path.pathtype = T_SubqueryScan;
1863 pathnode->path.parent = rel;
1864 pathnode->path.pathtarget = rel->reltarget;
1865 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1867 pathnode->path.parallel_aware = false;
1868 pathnode->path.parallel_safe = rel->consider_parallel &&
1869 subpath->parallel_safe;
1870 pathnode->path.parallel_workers = subpath->parallel_workers;
1871 pathnode->path.pathkeys = pathkeys;
1872 pathnode->subpath = subpath;
1873
1874 cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
1876
1877 return pathnode;
1878}
void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, bool trivial_pathtarget)
Definition costsize.c:1477

References RelOptInfo::consider_parallel, cost_subqueryscan(), fb(), get_baserel_parampathinfo(), makeNode, RelOptInfo::reltarget, root, and subpath().

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

◆ create_tablefuncscan_path()

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

Definition at line 1912 of file pathnode.c.

1914{
1916
1917 pathnode->pathtype = T_TableFuncScan;
1918 pathnode->parent = rel;
1919 pathnode->pathtarget = rel->reltarget;
1920 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1922 pathnode->parallel_aware = false;
1923 pathnode->parallel_safe = rel->consider_parallel;
1924 pathnode->parallel_workers = 0;
1925 pathnode->pathkeys = NIL; /* result is always unordered */
1926
1927 cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
1928
1929 return pathnode;
1930}
void cost_tablefuncscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1628

References RelOptInfo::consider_parallel, cost_tablefuncscan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

Referenced by set_tablefunc_pathlist().

◆ create_tidrangescan_path()

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

Definition at line 1262 of file pathnode.c.

1265{
1267
1268 pathnode->path.pathtype = T_TidRangeScan;
1269 pathnode->path.parent = rel;
1270 pathnode->path.pathtarget = rel->reltarget;
1271 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1273 pathnode->path.parallel_aware = (parallel_workers > 0);
1274 pathnode->path.parallel_safe = rel->consider_parallel;
1275 pathnode->path.parallel_workers = parallel_workers;
1276 pathnode->path.pathkeys = NIL; /* always unordered */
1277
1278 pathnode->tidrangequals = tidrangequals;
1279
1280 cost_tidrangescan(&pathnode->path, root, rel, tidrangequals,
1281 pathnode->path.param_info);
1282
1283 return pathnode;
1284}
void cost_tidrangescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, List *tidrangequals, ParamPathInfo *param_info)
Definition costsize.c:1360

References RelOptInfo::consider_parallel, cost_tidrangescan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

Referenced by create_tidscan_paths().

◆ create_tidscan_path()

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

Definition at line 1233 of file pathnode.c.

1235{
1237
1238 pathnode->path.pathtype = T_TidScan;
1239 pathnode->path.parent = rel;
1240 pathnode->path.pathtarget = rel->reltarget;
1241 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1243 pathnode->path.parallel_aware = false;
1244 pathnode->path.parallel_safe = rel->consider_parallel;
1245 pathnode->path.parallel_workers = 0;
1246 pathnode->path.pathkeys = NIL; /* always unordered */
1247
1248 pathnode->tidquals = tidquals;
1249
1250 cost_tidscan(&pathnode->path, root, rel, tidquals,
1251 pathnode->path.param_info);
1252
1253 return pathnode;
1254}
void cost_tidscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info)
Definition costsize.c:1250

References RelOptInfo::consider_parallel, cost_tidscan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

Referenced by BuildParameterizedTidPaths(), and create_tidscan_paths().

◆ create_unique_path()

UniquePath * create_unique_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
int  numCols,
double  numGroups 
)

Definition at line 2952 of file pathnode.c.

2957{
2959
2960 pathnode->path.pathtype = T_Unique;
2961 pathnode->path.parent = rel;
2962 /* Unique doesn't project, so use source path's pathtarget */
2963 pathnode->path.pathtarget = subpath->pathtarget;
2964 pathnode->path.param_info = subpath->param_info;
2965 pathnode->path.parallel_aware = false;
2966 pathnode->path.parallel_safe = rel->consider_parallel &&
2967 subpath->parallel_safe;
2968 pathnode->path.parallel_workers = subpath->parallel_workers;
2969 /* Unique doesn't change the input ordering */
2970 pathnode->path.pathkeys = subpath->pathkeys;
2971
2972 pathnode->subpath = subpath;
2973 pathnode->numkeys = numCols;
2974
2975 /*
2976 * Charge one cpu_operator_cost per comparison per input tuple. We assume
2977 * all columns get compared at most of the tuples. (XXX probably this is
2978 * an overestimate.)
2979 */
2980 pathnode->path.disabled_nodes = subpath->disabled_nodes;
2981 pathnode->path.startup_cost = subpath->startup_cost;
2982 pathnode->path.total_cost = subpath->total_cost +
2983 cpu_operator_cost * subpath->rows * numCols;
2984 pathnode->path.rows = numGroups;
2985
2986 return pathnode;
2987}

References RelOptInfo::consider_parallel, cpu_operator_cost, fb(), makeNode, and subpath().

Referenced by create_final_distinct_paths(), create_final_unique_paths(), create_partial_distinct_paths(), create_partial_unique_paths(), and generate_union_paths().

◆ create_valuesscan_path()

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

Definition at line 1938 of file pathnode.c.

1940{
1942
1943 pathnode->pathtype = T_ValuesScan;
1944 pathnode->parent = rel;
1945 pathnode->pathtarget = rel->reltarget;
1946 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1948 pathnode->parallel_aware = false;
1949 pathnode->parallel_safe = rel->consider_parallel;
1950 pathnode->parallel_workers = 0;
1951 pathnode->pathkeys = NIL; /* result is always unordered */
1952
1953 cost_valuesscan(pathnode, root, rel, pathnode->param_info);
1954
1955 return pathnode;
1956}
void cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1689

References RelOptInfo::consider_parallel, cost_valuesscan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

Referenced by set_values_pathlist().

◆ create_windowagg_path()

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

Definition at line 3340 of file pathnode.c.

3349{
3351
3352 /* qual can only be set for the topwindow */
3353 Assert(qual == NIL || topwindow);
3354
3355 pathnode->path.pathtype = T_WindowAgg;
3356 pathnode->path.parent = rel;
3357 pathnode->path.pathtarget = target;
3358 /* For now, assume we are above any joins, so no parameterization */
3359 pathnode->path.param_info = NULL;
3360 pathnode->path.parallel_aware = false;
3361 pathnode->path.parallel_safe = rel->consider_parallel &&
3362 subpath->parallel_safe;
3363 pathnode->path.parallel_workers = subpath->parallel_workers;
3364 /* WindowAgg preserves the input sort order */
3365 pathnode->path.pathkeys = subpath->pathkeys;
3366
3367 pathnode->subpath = subpath;
3368 pathnode->winclause = winclause;
3369 pathnode->qual = qual;
3370 pathnode->runCondition = runCondition;
3371 pathnode->topwindow = topwindow;
3372
3373 /*
3374 * For costing purposes, assume that there are no redundant partitioning
3375 * or ordering columns; it's not worth the trouble to deal with that
3376 * corner case here. So we just pass the unmodified list lengths to
3377 * cost_windowagg.
3378 */
3380 windowFuncs,
3381 winclause,
3382 subpath->disabled_nodes,
3383 subpath->startup_cost,
3384 subpath->total_cost,
3385 subpath->rows);
3386
3387 /* add tlist eval cost for each output row */
3388 pathnode->path.startup_cost += target->cost.startup;
3389 pathnode->path.total_cost += target->cost.startup +
3390 target->cost.per_tuple * pathnode->path.rows;
3391
3392 return pathnode;
3393}
void cost_windowagg(Path *path, PlannerInfo *root, List *windowFuncs, WindowClause *winclause, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition costsize.c:3203

References Assert, RelOptInfo::consider_parallel, PathTarget::cost, cost_windowagg(), fb(), makeNode, NIL, QualCost::per_tuple, root, QualCost::startup, and subpath().

Referenced by create_one_window_path().

◆ create_worktablescan_path()

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

Definition at line 2042 of file pathnode.c.

2044{
2046
2047 pathnode->pathtype = T_WorkTableScan;
2048 pathnode->parent = rel;
2049 pathnode->pathtarget = rel->reltarget;
2050 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2052 pathnode->parallel_aware = false;
2053 pathnode->parallel_safe = rel->consider_parallel;
2054 pathnode->parallel_workers = 0;
2055 pathnode->pathkeys = NIL; /* result is always unordered */
2056
2057 /* Cost is the same as for a regular CTE scan */
2058 cost_ctescan(pathnode, root, rel, pathnode->param_info);
2059
2060 return pathnode;
2061}

References RelOptInfo::consider_parallel, cost_ctescan(), fb(), get_baserel_parampathinfo(), makeNode, NIL, RelOptInfo::reltarget, and root.

Referenced by set_worktable_pathlist().

◆ path_is_reparameterizable_by_child()

bool path_is_reparameterizable_by_child ( Path path,
RelOptInfo child_rel 
)

Definition at line 4329 of file pathnode.c.

4330{
4331#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE(path) \
4332do { \
4333 if (!path_is_reparameterizable_by_child(path, child_rel)) \
4334 return false; \
4335} while(0)
4336
4337#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE(pathlist) \
4338do { \
4339 if (!pathlist_is_reparameterizable_by_child(pathlist, child_rel)) \
4340 return false; \
4341} while(0)
4342
4343 /*
4344 * If the path is not parameterized by the parent of the given relation,
4345 * it doesn't need reparameterization.
4346 */
4347 if (!path->param_info ||
4348 !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4349 return true;
4350
4351 /*
4352 * Check that the path type is one that reparameterize_path_by_child() can
4353 * handle, and recursively check subpaths.
4354 */
4355 switch (nodeTag(path))
4356 {
4357 case T_Path:
4358 case T_IndexPath:
4359 break;
4360
4361 case T_BitmapHeapPath:
4362 {
4364
4366 }
4367 break;
4368
4369 case T_BitmapAndPath:
4370 {
4372
4374 }
4375 break;
4376
4377 case T_BitmapOrPath:
4378 {
4379 BitmapOrPath *bopath = (BitmapOrPath *) path;
4380
4382 }
4383 break;
4384
4385 case T_ForeignPath:
4386 {
4387 ForeignPath *fpath = (ForeignPath *) path;
4388
4389 if (fpath->fdw_outerpath)
4391 }
4392 break;
4393
4394 case T_CustomPath:
4395 {
4396 CustomPath *cpath = (CustomPath *) path;
4397
4399 }
4400 break;
4401
4402 case T_NestPath:
4403 case T_MergePath:
4404 case T_HashPath:
4405 {
4406 JoinPath *jpath = (JoinPath *) path;
4407
4410 }
4411 break;
4412
4413 case T_AppendPath:
4414 {
4415 AppendPath *apath = (AppendPath *) path;
4416
4418 }
4419 break;
4420
4421 case T_MaterialPath:
4422 {
4423 MaterialPath *mpath = (MaterialPath *) path;
4424
4426 }
4427 break;
4428
4429 case T_MemoizePath:
4430 {
4431 MemoizePath *mpath = (MemoizePath *) path;
4432
4434 }
4435 break;
4436
4437 case T_GatherPath:
4438 {
4439 GatherPath *gpath = (GatherPath *) path;
4440
4442 }
4443 break;
4444
4445 default:
4446 /* We don't know how to reparameterize this path. */
4447 return false;
4448 }
4449
4450 return true;
4451}
#define nodeTag(nodeptr)
Definition nodes.h:139
#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE(pathlist)
#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE(path)
Path * outerjoinpath
Definition pathnodes.h:2390
Path * innerjoinpath
Definition pathnodes.h:2391

References bms_overlap(), fb(), JoinPath::innerjoinpath, nodeTag, JoinPath::outerjoinpath, PATH_REQ_OUTER, REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE, and REJECT_IF_PATH_NOT_REPARAMETERIZABLE.

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

◆ pathlist_is_reparameterizable_by_child()

static bool pathlist_is_reparameterizable_by_child ( List pathlist,
RelOptInfo child_rel 
)
static

Definition at line 4489 of file pathnode.c.

4490{
4491 ListCell *lc;
4492
4493 foreach(lc, pathlist)
4494 {
4495 Path *path = (Path *) lfirst(lc);
4496
4498 return false;
4499 }
4500
4501 return true;
4502}

References fb(), lfirst, and path_is_reparameterizable_by_child().

◆ reparameterize_path()

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

Definition at line 3863 of file pathnode.c.

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

References bms_is_subset(), 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(), Path::disabled_nodes, fb(), get_baserel_parampathinfo(), i, IsA, lappend(), lfirst, makeNode, SubqueryScanPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, reparameterize_path(), root, subpath(), SubqueryScanPath::subpath, and Path::total_cost.

Referenced by get_cheapest_parameterized_child_path(), and reparameterize_path().

◆ reparameterize_path_by_child()

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

Definition at line 4033 of file pathnode.c.

4035{
4036 Path *new_path;
4040
4041#define ADJUST_CHILD_ATTRS(node) \
4042 ((node) = (void *) adjust_appendrel_attrs_multilevel(root, \
4043 (Node *) (node), \
4044 child_rel, \
4045 child_rel->top_parent))
4046
4047#define REPARAMETERIZE_CHILD_PATH(path) \
4048do { \
4049 (path) = reparameterize_path_by_child(root, (path), child_rel); \
4050 if ((path) == NULL) \
4051 return NULL; \
4052} while(0)
4053
4054#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
4055do { \
4056 if ((pathlist) != NIL) \
4057 { \
4058 (pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
4059 child_rel); \
4060 if ((pathlist) == NIL) \
4061 return NULL; \
4062 } \
4063} while(0)
4064
4065 /*
4066 * If the path is not parameterized by the parent of the given relation,
4067 * it doesn't need reparameterization.
4068 */
4069 if (!path->param_info ||
4070 !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4071 return path;
4072
4073 /*
4074 * If possible, reparameterize the given path.
4075 *
4076 * This function is currently only applied to the inner side of a nestloop
4077 * join that is being partitioned by the partitionwise-join code. Hence,
4078 * we need only support path types that plausibly arise in that context.
4079 * (In particular, supporting sorted path types would be a waste of code
4080 * and cycles: even if we translated them here, they'd just lose in
4081 * subsequent cost comparisons.) If we do see an unsupported path type,
4082 * that just means we won't be able to generate a partitionwise-join plan
4083 * using that path type.
4084 */
4085 switch (nodeTag(path))
4086 {
4087 case T_Path:
4088 new_path = path;
4089 ADJUST_CHILD_ATTRS(new_path->parent->baserestrictinfo);
4090 if (path->pathtype == T_SampleScan)
4091 {
4092 Index scan_relid = path->parent->relid;
4094
4095 /* it should be a base rel with a tablesample clause... */
4096 Assert(scan_relid > 0);
4098 Assert(rte->rtekind == RTE_RELATION);
4099 Assert(rte->tablesample != NULL);
4100
4101 ADJUST_CHILD_ATTRS(rte->tablesample);
4102 }
4103 break;
4104
4105 case T_IndexPath:
4106 {
4107 IndexPath *ipath = (IndexPath *) path;
4108
4109 ADJUST_CHILD_ATTRS(ipath->indexinfo->indrestrictinfo);
4110 ADJUST_CHILD_ATTRS(ipath->indexclauses);
4111 new_path = (Path *) ipath;
4112 }
4113 break;
4114
4115 case T_BitmapHeapPath:
4116 {
4118
4119 ADJUST_CHILD_ATTRS(bhpath->path.parent->baserestrictinfo);
4120 REPARAMETERIZE_CHILD_PATH(bhpath->bitmapqual);
4121 new_path = (Path *) bhpath;
4122 }
4123 break;
4124
4125 case T_BitmapAndPath:
4126 {
4128
4130 new_path = (Path *) bapath;
4131 }
4132 break;
4133
4134 case T_BitmapOrPath:
4135 {
4136 BitmapOrPath *bopath = (BitmapOrPath *) path;
4137
4139 new_path = (Path *) bopath;
4140 }
4141 break;
4142
4143 case T_ForeignPath:
4144 {
4145 ForeignPath *fpath = (ForeignPath *) path;
4147
4148 ADJUST_CHILD_ATTRS(fpath->path.parent->baserestrictinfo);
4149 if (fpath->fdw_outerpath)
4150 REPARAMETERIZE_CHILD_PATH(fpath->fdw_outerpath);
4151 if (fpath->fdw_restrictinfo)
4152 ADJUST_CHILD_ATTRS(fpath->fdw_restrictinfo);
4153
4154 /* Hand over to FDW if needed. */
4155 rfpc_func =
4156 path->parent->fdwroutine->ReparameterizeForeignPathByChild;
4157 if (rfpc_func)
4158 fpath->fdw_private = rfpc_func(root, fpath->fdw_private,
4159 child_rel);
4160 new_path = (Path *) fpath;
4161 }
4162 break;
4163
4164 case T_CustomPath:
4165 {
4166 CustomPath *cpath = (CustomPath *) path;
4167
4168 ADJUST_CHILD_ATTRS(cpath->path.parent->baserestrictinfo);
4170 if (cpath->custom_restrictinfo)
4171 ADJUST_CHILD_ATTRS(cpath->custom_restrictinfo);
4172 if (cpath->methods &&
4173 cpath->methods->ReparameterizeCustomPathByChild)
4174 cpath->custom_private =
4175 cpath->methods->ReparameterizeCustomPathByChild(root,
4176 cpath->custom_private,
4177 child_rel);
4178 new_path = (Path *) cpath;
4179 }
4180 break;
4181
4182 case T_NestPath:
4183 {
4184 NestPath *npath = (NestPath *) path;
4185 JoinPath *jpath = (JoinPath *) npath;
4186
4190 new_path = (Path *) npath;
4191 }
4192 break;
4193
4194 case T_MergePath:
4195 {
4196 MergePath *mpath = (MergePath *) path;
4197 JoinPath *jpath = (JoinPath *) mpath;
4198
4202 ADJUST_CHILD_ATTRS(mpath->path_mergeclauses);
4203 new_path = (Path *) mpath;
4204 }
4205 break;
4206
4207 case T_HashPath:
4208 {
4209 HashPath *hpath = (HashPath *) path;
4210 JoinPath *jpath = (JoinPath *) hpath;
4211
4215 ADJUST_CHILD_ATTRS(hpath->path_hashclauses);
4216 new_path = (Path *) hpath;
4217 }
4218 break;
4219
4220 case T_AppendPath:
4221 {
4222 AppendPath *apath = (AppendPath *) path;
4223
4225 new_path = (Path *) apath;
4226 }
4227 break;
4228
4229 case T_MaterialPath:
4230 {
4231 MaterialPath *mpath = (MaterialPath *) path;
4232
4234 new_path = (Path *) mpath;
4235 }
4236 break;
4237
4238 case T_MemoizePath:
4239 {
4240 MemoizePath *mpath = (MemoizePath *) path;
4241
4243 ADJUST_CHILD_ATTRS(mpath->param_exprs);
4244 new_path = (Path *) mpath;
4245 }
4246 break;
4247
4248 case T_GatherPath:
4249 {
4250 GatherPath *gpath = (GatherPath *) path;
4251
4253 new_path = (Path *) gpath;
4254 }
4255 break;
4256
4257 default:
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;
4270 child_rel,
4271 child_rel->top_parent);
4272
4273 /* If we already have a PPI for this parameterization, just return it */
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
4287
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 }
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:659
void bms_free(Bitmapset *a)
Definition bitmapset.c:239
unsigned int Index
Definition c.h:628
List *(* ReparameterizeForeignPathByChild_function)(PlannerInfo *root, List *fdw_private, RelOptInfo *child_rel)
Definition fdwapi.h:182
MemoryContext GetMemoryChunkContext(void *pointer)
Definition mcxt.c:756
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
@ RTE_RELATION
#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist)
#define REPARAMETERIZE_CHILD_PATH(path)
#define ADJUST_CHILD_ATTRS(node)
#define planner_rt_fetch(rti, root)
Definition pathnodes.h:692
ParamPathInfo * find_param_path_info(RelOptInfo *rel, Relids required_outer)
Definition relnode.c:2037
List * joinrestrictinfo
Definition pathnodes.h:2393
List * ppilist
Definition pathnodes.h:1039
PathTarget * copy_pathtarget(PathTarget *src)
Definition tlist.c:666

References ADJUST_CHILD_ATTRS, adjust_child_relids_multilevel(), Assert, bms_copy(), bms_free(), bms_overlap(), copy_pathtarget(), fb(), find_param_path_info(), GetMemoryChunkContext(), JoinPath::innerjoinpath, JoinPath::joinrestrictinfo, lappend(), makeNode, MemoryContextSwitchTo(), nodeTag, JoinPath::outerjoinpath, PATH_REQ_OUTER, Path::pathtype, planner_rt_fetch, RelOptInfo::ppilist, REPARAMETERIZE_CHILD_PATH, REPARAMETERIZE_CHILD_PATH_LIST, root, and RTE_RELATION.

Referenced by create_nestloop_plan(), and reparameterize_pathlist_by_child().

◆ reparameterize_pathlist_by_child()

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

Definition at line 4460 of file pathnode.c.

4463{
4464 ListCell *lc;
4465 List *result = NIL;
4466
4467 foreach(lc, pathlist)
4468 {
4470 child_rel);
4471
4472 if (path == NULL)
4473 {
4474 list_free(result);
4475 return NIL;
4476 }
4477
4478 result = lappend(result, path);
4479 }
4480
4481 return result;
4482}
void list_free(List *list)
Definition list.c:1546

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

◆ set_cheapest()

void set_cheapest ( RelOptInfo parent_rel)

Definition at line 268 of file pathnode.c.

269{
270 Path *cheapest_startup_path;
271 Path *cheapest_total_path;
274 ListCell *p;
275
277
278 if (parent_rel->pathlist == NIL)
279 elog(ERROR, "could not devise a query plan for the given query");
280
281 cheapest_startup_path = cheapest_total_path = best_param_path = NULL;
283
284 foreach(p, parent_rel->pathlist)
285 {
286 Path *path = (Path *) lfirst(p);
287 int cmp;
288
289 if (path->param_info)
290 {
291 /* Parameterized path, so add it to parameterized_paths */
293
294 /*
295 * If we have an unparameterized cheapest-total, we no longer care
296 * about finding the best parameterized path, so move on.
297 */
298 if (cheapest_total_path)
299 continue;
300
301 /*
302 * Otherwise, track the best parameterized path, which is the one
303 * with least total cost among those of the minimum
304 * parameterization.
305 */
306 if (best_param_path == NULL)
307 best_param_path = path;
308 else
309 {
312 {
313 case BMS_EQUAL:
314 /* keep the cheaper one */
316 TOTAL_COST) < 0)
317 best_param_path = path;
318 break;
319 case BMS_SUBSET1:
320 /* new path is less-parameterized */
321 best_param_path = path;
322 break;
323 case BMS_SUBSET2:
324 /* old path is less-parameterized, keep it */
325 break;
326 case BMS_DIFFERENT:
327
328 /*
329 * This means that neither path has the least possible
330 * parameterization for the rel. We'll sit on the old
331 * path until something better comes along.
332 */
333 break;
334 }
335 }
336 }
337 else
338 {
339 /* Unparameterized path, so consider it for cheapest slots */
340 if (cheapest_total_path == NULL)
341 {
342 cheapest_startup_path = cheapest_total_path = path;
343 continue;
344 }
345
346 /*
347 * If we find two paths of identical costs, try to keep the
348 * better-sorted one. The paths might have unrelated sort
349 * orderings, in which case we can only guess which might be
350 * better to keep, but if one is superior then we definitely
351 * should keep that one.
352 */
353 cmp = compare_path_costs(cheapest_startup_path, path, STARTUP_COST);
354 if (cmp > 0 ||
355 (cmp == 0 &&
356 compare_pathkeys(cheapest_startup_path->pathkeys,
357 path->pathkeys) == PATHKEYS_BETTER2))
358 cheapest_startup_path = path;
359
360 cmp = compare_path_costs(cheapest_total_path, path, TOTAL_COST);
361 if (cmp > 0 ||
362 (cmp == 0 &&
363 compare_pathkeys(cheapest_total_path->pathkeys,
364 path->pathkeys) == PATHKEYS_BETTER2))
365 cheapest_total_path = path;
366 }
367 }
368
369 /* Add cheapest unparameterized path, if any, to parameterized_paths */
370 if (cheapest_total_path)
371 parameterized_paths = lcons(cheapest_total_path, parameterized_paths);
372
373 /*
374 * If there is no unparameterized path, use the best parameterized path as
375 * cheapest_total_path (but not as cheapest_startup_path).
376 */
377 if (cheapest_total_path == NULL)
378 cheapest_total_path = best_param_path;
379 Assert(cheapest_total_path != NULL);
380
381 parent_rel->cheapest_startup_path = cheapest_startup_path;
382 parent_rel->cheapest_total_path = cheapest_total_path;
383 parent_rel->cheapest_parameterized_paths = parameterized_paths;
384}
@ BMS_DIFFERENT
Definition bitmapset.h:65
List * lcons(void *datum, List *list)
Definition list.c:495

References Assert, BMS_DIFFERENT, BMS_EQUAL, BMS_SUBSET1, BMS_SUBSET2, bms_subset_compare(), cmp(), compare_path_costs(), compare_pathkeys(), elog, ERROR, fb(), IsA, lappend(), lcons(), lfirst, NIL, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER2, 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_partial_unique_paths(), create_partitionwise_grouping_paths(), create_unique_paths(), create_window_paths(), generate_partitionwise_join_paths(), mark_dummy_rel(), merge_clump(), postprocess_setop_rel(), query_planner(), set_dummy_rel_pathlist(), set_grouped_rel_pathlist(), set_rel_pathlist(), standard_join_search(), and subquery_planner().