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, List *subpaths, List *partial_subpaths, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath, 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:4485

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

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

◆ 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:4456
#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:1995
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 3792 of file pathnode.c.

3797{
3798 double input_rows = *rows;
3799 Cost input_startup_cost = *startup_cost;
3800 Cost input_total_cost = *total_cost;
3801
3802 if (offset_est != 0)
3803 {
3804 double offset_rows;
3805
3806 if (offset_est > 0)
3807 offset_rows = (double) offset_est;
3808 else
3810 if (offset_rows > *rows)
3811 offset_rows = *rows;
3812 if (input_rows > 0)
3813 *startup_cost +=
3816 *rows -= offset_rows;
3817 if (*rows < 1)
3818 *rows = 1;
3819 }
3820
3821 if (count_est != 0)
3822 {
3823 double count_rows;
3824
3825 if (count_est > 0)
3826 count_rows = (double) count_est;
3827 else
3829 if (count_rows > *rows)
3830 count_rows = *rows;
3831 if (input_rows > 0)
3832 *total_cost = *startup_cost +
3835 *rows = count_rows;
3836 if (*rows < 1)
3837 *rows = 1;
3838 }
3839}
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 1452 of file pathnode.c.

1453{
1454 Path *path1 = (Path *) lfirst(a);
1455 Path *path2 = (Path *) lfirst(b);
1456 int cmp;
1457
1459 if (cmp != 0)
1460 return -cmp;
1461 return bms_compare(path1->parent->relids, path2->parent->relids);
1462}
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 1430 of file pathnode.c.

1431{
1432 Path *path1 = (Path *) lfirst(a);
1433 Path *path2 = (Path *) lfirst(b);
1434 int cmp;
1435
1437 if (cmp != 0)
1438 return -cmp;
1439 return bms_compare(path1->parent->relids, path2->parent->relids);
1440}
@ 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 2640 of file pathnode.c.

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

2225{
2227
2228 /* inner_path can require rels from outer path, but not vice versa */
2230 /* easy case if inner path is not parameterized */
2231 if (!inner_paramrels)
2232 return bms_copy(outer_paramrels);
2233 /* else, form the union ... */
2235 /* ... and remove any mention of now-satisfied outer rels */
2237 outerrelids);
2238 return required_outer;
2239}
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 2248 of file pathnode.c.

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

3011{
3013
3014 pathnode->path.pathtype = T_Agg;
3015 pathnode->path.parent = rel;
3016 pathnode->path.pathtarget = target;
3017 pathnode->path.param_info = subpath->param_info;
3018 pathnode->path.parallel_aware = false;
3019 pathnode->path.parallel_safe = rel->consider_parallel &&
3020 subpath->parallel_safe;
3021 pathnode->path.parallel_workers = subpath->parallel_workers;
3022
3023 if (aggstrategy == AGG_SORTED)
3024 {
3025 /*
3026 * Attempt to preserve the order of the subpath. Additional pathkeys
3027 * may have been added in adjust_group_pathkeys_for_groupagg() to
3028 * support ORDER BY / DISTINCT aggregates. Pathkeys added there
3029 * belong to columns within the aggregate function, so we must strip
3030 * these additional pathkeys off as those columns are unavailable
3031 * above the aggregate node.
3032 */
3033 if (list_length(subpath->pathkeys) > root->num_groupby_pathkeys)
3034 pathnode->path.pathkeys = list_copy_head(subpath->pathkeys,
3035 root->num_groupby_pathkeys);
3036 else
3037 pathnode->path.pathkeys = subpath->pathkeys; /* preserves order */
3038 }
3039 else
3040 pathnode->path.pathkeys = NIL; /* output is unordered */
3041
3042 pathnode->subpath = subpath;
3043
3044 pathnode->aggstrategy = aggstrategy;
3045 pathnode->aggsplit = aggsplit;
3046 pathnode->numGroups = numGroups;
3047 pathnode->transitionSpace = aggcosts ? aggcosts->transitionSpace : 0;
3048 pathnode->groupClause = groupClause;
3049 pathnode->qual = qual;
3050
3051 cost_agg(&pathnode->path, root,
3052 aggstrategy, aggcosts,
3053 list_length(groupClause), numGroups,
3054 qual,
3055 subpath->disabled_nodes,
3056 subpath->startup_cost, subpath->total_cost,
3057 subpath->rows, subpath->pathtarget->width);
3058
3059 /* add tlist eval cost for each output row */
3060 pathnode->path.startup_cost += target->cost.startup;
3061 pathnode->path.total_cost += target->cost.startup +
3062 target->cost.per_tuple * pathnode->path.rows;
3063
3064 return pathnode;
3065}
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:2792
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:1019

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

References append_startup_cost_compare(), append_total_cost_compare(), Assert, bms_equal(), RelOptInfo::consider_parallel, cost_append(), fb(), get_appendrel_parampathinfo(), get_baserel_parampathinfo(), 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 1961 of file pathnode.c.

1963{
1965
1966 pathnode->pathtype = T_CteScan;
1967 pathnode->parent = rel;
1968 pathnode->pathtarget = rel->reltarget;
1969 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1971 pathnode->parallel_aware = false;
1972 pathnode->parallel_safe = rel->consider_parallel;
1973 pathnode->parallel_workers = 0;
1974 pathnode->pathkeys = pathkeys;
1975
1976 cost_ctescan(pathnode, root, rel, pathnode->param_info);
1977
1978 return pathnode;
1979}
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 2120 of file pathnode.c.

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

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

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

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

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

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

1885{
1887
1888 pathnode->pathtype = T_FunctionScan;
1889 pathnode->parent = rel;
1890 pathnode->pathtarget = rel->reltarget;
1891 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1893 pathnode->parallel_aware = false;
1894 pathnode->parallel_safe = rel->consider_parallel;
1895 pathnode->parallel_workers = 0;
1896 pathnode->pathkeys = pathkeys;
1897
1898 cost_functionscan(pathnode, root, rel, pathnode->param_info);
1899
1900 return pathnode;
1901}
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 1757 of file pathnode.c.

1760{
1762 int input_disabled_nodes = 0;
1765
1766 Assert(subpath->parallel_safe);
1767 Assert(pathkeys);
1768
1769 /*
1770 * The subpath should guarantee that it is adequately ordered either by
1771 * adding an explicit sort node or by using presorted input. We cannot
1772 * add an explicit Sort node for the subpath in createplan.c on additional
1773 * pathkeys, because we can't guarantee the sort would be safe. For
1774 * example, expressions may be volatile or otherwise parallel unsafe.
1775 */
1776 if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
1777 elog(ERROR, "gather merge input not sufficiently sorted");
1778
1779 pathnode->path.pathtype = T_GatherMerge;
1780 pathnode->path.parent = rel;
1781 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1783 pathnode->path.parallel_aware = false;
1784
1785 pathnode->subpath = subpath;
1786 pathnode->num_workers = subpath->parallel_workers;
1787 pathnode->path.pathkeys = pathkeys;
1788 pathnode->path.pathtarget = target ? target : rel->reltarget;
1789
1790 input_disabled_nodes += subpath->disabled_nodes;
1791 input_startup_cost += subpath->startup_cost;
1792 input_total_cost += subpath->total_cost;
1793
1794 cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
1796 input_total_cost, rows);
1797
1798 return pathnode;
1799}
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 1809 of file pathnode.c.

1811{
1813
1814 Assert(subpath->parallel_safe);
1815
1816 pathnode->path.pathtype = T_Gather;
1817 pathnode->path.parent = rel;
1818 pathnode->path.pathtarget = target;
1819 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1821 pathnode->path.parallel_aware = false;
1822 pathnode->path.parallel_safe = false;
1823 pathnode->path.parallel_workers = 0;
1824 pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1825
1826 pathnode->subpath = subpath;
1827 pathnode->num_workers = subpath->parallel_workers;
1828 pathnode->single_copy = false;
1829
1830 if (pathnode->num_workers == 0)
1831 {
1832 pathnode->path.pathkeys = subpath->pathkeys;
1833 pathnode->num_workers = 1;
1834 pathnode->single_copy = true;
1835 }
1836
1837 cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1838
1839 return pathnode;
1840}
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 2892 of file pathnode.c.

2898{
2900 PathTarget *target = rel->reltarget;
2901
2902 pathnode->path.pathtype = T_Group;
2903 pathnode->path.parent = rel;
2904 pathnode->path.pathtarget = target;
2905 /* For now, assume we are above any joins, so no parameterization */
2906 pathnode->path.param_info = NULL;
2907 pathnode->path.parallel_aware = false;
2908 pathnode->path.parallel_safe = rel->consider_parallel &&
2909 subpath->parallel_safe;
2910 pathnode->path.parallel_workers = subpath->parallel_workers;
2911 /* Group doesn't change sort ordering */
2912 pathnode->path.pathkeys = subpath->pathkeys;
2913
2914 pathnode->subpath = subpath;
2915
2916 pathnode->groupClause = groupClause;
2917 pathnode->qual = qual;
2918
2919 cost_group(&pathnode->path, root,
2920 list_length(groupClause),
2921 numGroups,
2922 qual,
2923 subpath->disabled_nodes,
2924 subpath->startup_cost, subpath->total_cost,
2925 subpath->rows);
2926
2927 /* add tlist eval cost for each output row */
2928 pathnode->path.startup_cost += target->cost.startup;
2929 pathnode->path.total_cost += target->cost.startup +
2930 target->cost.per_tuple * pathnode->path.rows;
2931
2932 return pathnode;
2933}
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:3305

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

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

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

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

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

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

2805{
2807 SortPath *pathnode = &sort->spath;
2808
2810 pathnode->path.parent = rel;
2811 /* Sort doesn't project, so use source path's pathtarget */
2812 pathnode->path.pathtarget = subpath->pathtarget;
2813 pathnode->path.param_info = subpath->param_info;
2814 pathnode->path.parallel_aware = false;
2815 pathnode->path.parallel_safe = rel->consider_parallel &&
2816 subpath->parallel_safe;
2817 pathnode->path.parallel_workers = subpath->parallel_workers;
2818 pathnode->path.pathkeys = pathkeys;
2819
2820 pathnode->subpath = subpath;
2821
2823 root, pathkeys, presorted_keys,
2824 subpath->disabled_nodes,
2825 subpath->startup_cost,
2826 subpath->total_cost,
2827 subpath->rows,
2828 subpath->pathtarget->width,
2829 0.0, /* XXX comparison_cost shouldn't be 0? */
2830 work_mem, limit_tuples);
2831
2832 sort->nPresortedCols = presorted_keys;
2833
2834 return sort;
2835}
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:1951
Path path
Definition pathnodes.h:2507

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

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

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

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

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

1657{
1659
1660 Assert(subpath->parent == rel);
1661
1662 pathnode->path.pathtype = T_Material;
1663 pathnode->path.parent = rel;
1664 pathnode->path.pathtarget = rel->reltarget;
1665 pathnode->path.param_info = subpath->param_info;
1666 pathnode->path.parallel_aware = false;
1667 pathnode->path.parallel_safe = rel->consider_parallel &&
1668 subpath->parallel_safe;
1669 pathnode->path.parallel_workers = subpath->parallel_workers;
1670 pathnode->path.pathkeys = subpath->pathkeys;
1671
1672 pathnode->subpath = subpath;
1673
1674 cost_material(&pathnode->path,
1675 enabled,
1676 subpath->disabled_nodes,
1677 subpath->startup_cost,
1678 subpath->total_cost,
1679 subpath->rows,
1680 subpath->pathtarget->width);
1681
1682 return pathnode;
1683}
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 1690 of file pathnode.c.

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

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 pathkeys,
Relids  required_outer 
)

Definition at line 1470 of file pathnode.c.

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

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

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

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

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

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

1989{
1991
1992 pathnode->pathtype = T_NamedTuplestoreScan;
1993 pathnode->parent = rel;
1994 pathnode->pathtarget = rel->reltarget;
1995 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1997 pathnode->parallel_aware = false;
1998 pathnode->parallel_safe = rel->consider_parallel;
1999 pathnode->parallel_workers = 0;
2000 pathnode->pathkeys = NIL; /* result is always unordered */
2001
2002 cost_namedtuplestorescan(pathnode, root, rel, pathnode->param_info);
2003
2004 return pathnode;
2005}
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 2300 of file pathnode.c.

2310{
2313 Relids outerrelids;
2314
2315 /*
2316 * Paths are parameterized by top-level parents, so run parameterization
2317 * tests on the parent relids.
2318 */
2319 if (outer_path->parent->top_parent_relids)
2320 outerrelids = outer_path->parent->top_parent_relids;
2321 else
2322 outerrelids = outer_path->parent->relids;
2323
2324 /*
2325 * If the inner path is parameterized by the outer, we must drop any
2326 * restrict_clauses that are due to be moved into the inner path. We have
2327 * to do this now, rather than postpone the work till createplan time,
2328 * because the restrict_clauses list can affect the size and cost
2329 * estimates for this path. We detect such clauses by checking for serial
2330 * number match to clauses already enforced in the inner path.
2331 */
2332 if (bms_overlap(inner_req_outer, outerrelids))
2333 {
2335 List *jclauses = NIL;
2336 ListCell *lc;
2337
2338 foreach(lc, restrict_clauses)
2339 {
2340 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2341
2343 jclauses = lappend(jclauses, rinfo);
2344 }
2346 }
2347
2348 pathnode->jpath.path.pathtype = T_NestLoop;
2349 pathnode->jpath.path.parent = joinrel;
2350 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2351 pathnode->jpath.path.param_info =
2353 joinrel,
2354 outer_path,
2355 inner_path,
2356 extra->sjinfo,
2359 pathnode->jpath.path.parallel_aware = false;
2360 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2361 outer_path->parallel_safe && inner_path->parallel_safe;
2362 /* This is a foolish way to estimate parallel_workers, but for now... */
2363 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2364 pathnode->jpath.path.pathkeys = pathkeys;
2365 pathnode->jpath.jointype = jointype;
2366 pathnode->jpath.inner_unique = extra->inner_unique;
2367 pathnode->jpath.outerjoinpath = outer_path;
2368 pathnode->jpath.innerjoinpath = inner_path;
2369 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2370
2371 final_cost_nestloop(root, pathnode, workspace, extra);
2372
2373 return pathnode;
2374}
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:3459
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 2531 of file pathnode.c.

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

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

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

2015{
2017
2018 pathnode->pathtype = T_Result;
2019 pathnode->parent = rel;
2020 pathnode->pathtarget = rel->reltarget;
2021 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2023 pathnode->parallel_aware = false;
2024 pathnode->parallel_safe = rel->consider_parallel;
2025 pathnode->parallel_workers = 0;
2026 pathnode->pathkeys = NIL; /* result is always unordered */
2027
2028 cost_resultscan(pathnode, root, rel, pathnode->param_info);
2029
2030 return pathnode;
2031}
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 2729 of file pathnode.c.

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

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

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

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

1856{
1858
1859 pathnode->path.pathtype = T_SubqueryScan;
1860 pathnode->path.parent = rel;
1861 pathnode->path.pathtarget = rel->reltarget;
1862 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1864 pathnode->path.parallel_aware = false;
1865 pathnode->path.parallel_safe = rel->consider_parallel &&
1866 subpath->parallel_safe;
1867 pathnode->path.parallel_workers = subpath->parallel_workers;
1868 pathnode->path.pathkeys = pathkeys;
1869 pathnode->subpath = subpath;
1870
1871 cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
1873
1874 return pathnode;
1875}
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 1909 of file pathnode.c.

1911{
1913
1914 pathnode->pathtype = T_TableFuncScan;
1915 pathnode->parent = rel;
1916 pathnode->pathtarget = rel->reltarget;
1917 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1919 pathnode->parallel_aware = false;
1920 pathnode->parallel_safe = rel->consider_parallel;
1921 pathnode->parallel_workers = 0;
1922 pathnode->pathkeys = NIL; /* result is always unordered */
1923
1924 cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
1925
1926 return pathnode;
1927}
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 2949 of file pathnode.c.

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

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

1937{
1939
1940 pathnode->pathtype = T_ValuesScan;
1941 pathnode->parent = rel;
1942 pathnode->pathtarget = rel->reltarget;
1943 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1945 pathnode->parallel_aware = false;
1946 pathnode->parallel_safe = rel->consider_parallel;
1947 pathnode->parallel_workers = 0;
1948 pathnode->pathkeys = NIL; /* result is always unordered */
1949
1950 cost_valuesscan(pathnode, root, rel, pathnode->param_info);
1951
1952 return pathnode;
1953}
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 3337 of file pathnode.c.

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

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

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

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

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

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

4486{
4487 ListCell *lc;
4488
4489 foreach(lc, pathlist)
4490 {
4491 Path *path = (Path *) lfirst(lc);
4492
4494 return false;
4495 }
4496
4497 return true;
4498}

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

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

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, NIL, 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 4029 of file pathnode.c.

4031{
4032 Path *new_path;
4036
4037#define ADJUST_CHILD_ATTRS(node) \
4038 ((node) = (void *) adjust_appendrel_attrs_multilevel(root, \
4039 (Node *) (node), \
4040 child_rel, \
4041 child_rel->top_parent))
4042
4043#define REPARAMETERIZE_CHILD_PATH(path) \
4044do { \
4045 (path) = reparameterize_path_by_child(root, (path), child_rel); \
4046 if ((path) == NULL) \
4047 return NULL; \
4048} while(0)
4049
4050#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
4051do { \
4052 if ((pathlist) != NIL) \
4053 { \
4054 (pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
4055 child_rel); \
4056 if ((pathlist) == NIL) \
4057 return NULL; \
4058 } \
4059} while(0)
4060
4061 /*
4062 * If the path is not parameterized by the parent of the given relation,
4063 * it doesn't need reparameterization.
4064 */
4065 if (!path->param_info ||
4066 !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4067 return path;
4068
4069 /*
4070 * If possible, reparameterize the given path.
4071 *
4072 * This function is currently only applied to the inner side of a nestloop
4073 * join that is being partitioned by the partitionwise-join code. Hence,
4074 * we need only support path types that plausibly arise in that context.
4075 * (In particular, supporting sorted path types would be a waste of code
4076 * and cycles: even if we translated them here, they'd just lose in
4077 * subsequent cost comparisons.) If we do see an unsupported path type,
4078 * that just means we won't be able to generate a partitionwise-join plan
4079 * using that path type.
4080 */
4081 switch (nodeTag(path))
4082 {
4083 case T_Path:
4084 new_path = path;
4085 ADJUST_CHILD_ATTRS(new_path->parent->baserestrictinfo);
4086 if (path->pathtype == T_SampleScan)
4087 {
4088 Index scan_relid = path->parent->relid;
4090
4091 /* it should be a base rel with a tablesample clause... */
4092 Assert(scan_relid > 0);
4094 Assert(rte->rtekind == RTE_RELATION);
4095 Assert(rte->tablesample != NULL);
4096
4097 ADJUST_CHILD_ATTRS(rte->tablesample);
4098 }
4099 break;
4100
4101 case T_IndexPath:
4102 {
4103 IndexPath *ipath = (IndexPath *) path;
4104
4105 ADJUST_CHILD_ATTRS(ipath->indexinfo->indrestrictinfo);
4106 ADJUST_CHILD_ATTRS(ipath->indexclauses);
4107 new_path = (Path *) ipath;
4108 }
4109 break;
4110
4111 case T_BitmapHeapPath:
4112 {
4114
4115 ADJUST_CHILD_ATTRS(bhpath->path.parent->baserestrictinfo);
4116 REPARAMETERIZE_CHILD_PATH(bhpath->bitmapqual);
4117 new_path = (Path *) bhpath;
4118 }
4119 break;
4120
4121 case T_BitmapAndPath:
4122 {
4124
4126 new_path = (Path *) bapath;
4127 }
4128 break;
4129
4130 case T_BitmapOrPath:
4131 {
4132 BitmapOrPath *bopath = (BitmapOrPath *) path;
4133
4135 new_path = (Path *) bopath;
4136 }
4137 break;
4138
4139 case T_ForeignPath:
4140 {
4141 ForeignPath *fpath = (ForeignPath *) path;
4143
4144 ADJUST_CHILD_ATTRS(fpath->path.parent->baserestrictinfo);
4145 if (fpath->fdw_outerpath)
4146 REPARAMETERIZE_CHILD_PATH(fpath->fdw_outerpath);
4147 if (fpath->fdw_restrictinfo)
4148 ADJUST_CHILD_ATTRS(fpath->fdw_restrictinfo);
4149
4150 /* Hand over to FDW if needed. */
4151 rfpc_func =
4152 path->parent->fdwroutine->ReparameterizeForeignPathByChild;
4153 if (rfpc_func)
4154 fpath->fdw_private = rfpc_func(root, fpath->fdw_private,
4155 child_rel);
4156 new_path = (Path *) fpath;
4157 }
4158 break;
4159
4160 case T_CustomPath:
4161 {
4162 CustomPath *cpath = (CustomPath *) path;
4163
4164 ADJUST_CHILD_ATTRS(cpath->path.parent->baserestrictinfo);
4166 if (cpath->custom_restrictinfo)
4167 ADJUST_CHILD_ATTRS(cpath->custom_restrictinfo);
4168 if (cpath->methods &&
4169 cpath->methods->ReparameterizeCustomPathByChild)
4170 cpath->custom_private =
4171 cpath->methods->ReparameterizeCustomPathByChild(root,
4172 cpath->custom_private,
4173 child_rel);
4174 new_path = (Path *) cpath;
4175 }
4176 break;
4177
4178 case T_NestPath:
4179 {
4180 NestPath *npath = (NestPath *) path;
4181 JoinPath *jpath = (JoinPath *) npath;
4182
4186 new_path = (Path *) npath;
4187 }
4188 break;
4189
4190 case T_MergePath:
4191 {
4192 MergePath *mpath = (MergePath *) path;
4193 JoinPath *jpath = (JoinPath *) mpath;
4194
4198 ADJUST_CHILD_ATTRS(mpath->path_mergeclauses);
4199 new_path = (Path *) mpath;
4200 }
4201 break;
4202
4203 case T_HashPath:
4204 {
4205 HashPath *hpath = (HashPath *) path;
4206 JoinPath *jpath = (JoinPath *) hpath;
4207
4211 ADJUST_CHILD_ATTRS(hpath->path_hashclauses);
4212 new_path = (Path *) hpath;
4213 }
4214 break;
4215
4216 case T_AppendPath:
4217 {
4218 AppendPath *apath = (AppendPath *) path;
4219
4221 new_path = (Path *) apath;
4222 }
4223 break;
4224
4225 case T_MaterialPath:
4226 {
4227 MaterialPath *mpath = (MaterialPath *) path;
4228
4230 new_path = (Path *) mpath;
4231 }
4232 break;
4233
4234 case T_MemoizePath:
4235 {
4236 MemoizePath *mpath = (MemoizePath *) path;
4237
4239 ADJUST_CHILD_ATTRS(mpath->param_exprs);
4240 new_path = (Path *) mpath;
4241 }
4242 break;
4243
4244 case T_GatherPath:
4245 {
4246 GatherPath *gpath = (GatherPath *) path;
4247
4249 new_path = (Path *) gpath;
4250 }
4251 break;
4252
4253 default:
4254 /* We don't know how to reparameterize this path. */
4255 return NULL;
4256 }
4257
4258 /*
4259 * Adjust the parameterization information, which refers to the topmost
4260 * parent. The topmost parent can be multiple levels away from the given
4261 * child, hence use multi-level expression adjustment routines.
4262 */
4263 old_ppi = new_path->param_info;
4266 child_rel,
4267 child_rel->top_parent);
4268
4269 /* If we already have a PPI for this parameterization, just return it */
4271
4272 /*
4273 * If not, build a new one and link it to the list of PPIs. For the same
4274 * reason as explained in mark_dummy_rel(), allocate new PPI in the same
4275 * context the given RelOptInfo is in.
4276 */
4277 if (new_ppi == NULL)
4278 {
4279 MemoryContext oldcontext;
4280 RelOptInfo *rel = path->parent;
4281
4283
4285 new_ppi->ppi_req_outer = bms_copy(required_outer);
4286 new_ppi->ppi_rows = old_ppi->ppi_rows;
4287 new_ppi->ppi_clauses = old_ppi->ppi_clauses;
4288 ADJUST_CHILD_ATTRS(new_ppi->ppi_clauses);
4289 new_ppi->ppi_serials = bms_copy(old_ppi->ppi_serials);
4290 rel->ppilist = lappend(rel->ppilist, new_ppi);
4291
4292 MemoryContextSwitchTo(oldcontext);
4293 }
4295
4296 new_path->param_info = new_ppi;
4297
4298 /*
4299 * Adjust the path target if the parent of the outer relation is
4300 * referenced in the targetlist. This can happen when only the parent of
4301 * outer relation is laterally referenced in this relation.
4302 */
4303 if (bms_overlap(path->parent->lateral_relids,
4304 child_rel->top_parent_relids))
4305 {
4306 new_path->pathtarget = copy_pathtarget(new_path->pathtarget);
4307 ADJUST_CHILD_ATTRS(new_path->pathtarget->exprs);
4308 }
4309
4310 return new_path;
4311}
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:686
ParamPathInfo * find_param_path_info(RelOptInfo *rel, Relids required_outer)
Definition relnode.c:2037
List * joinrestrictinfo
Definition pathnodes.h:2377
List * ppilist
Definition pathnodes.h:1033
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 4456 of file pathnode.c.

4459{
4460 ListCell *lc;
4461 List *result = NIL;
4462
4463 foreach(lc, pathlist)
4464 {
4466 child_rel);
4467
4468 if (path == NULL)
4469 {
4470 list_free(result);
4471 return NIL;
4472 }
4473
4474 result = lappend(result, path);
4475 }
4476
4477 return result;
4478}
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().