PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pathnode.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "executor/nodeSetOp.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/extensible.h"
#include "optimizer/appendinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/tlist.h"
#include "parser/parsetree.h"
#include "utils/memutils.h"
#include "utils/selfuncs.h"
Include dependency graph for pathnode.c:

Go to the source code of this file.

Macros

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

Enumerations

enum  PathCostComparison { COSTS_EQUAL , COSTS_BETTER1 , COSTS_BETTER2 , COSTS_DIFFERENT }
 

Functions

static int append_total_cost_compare (const ListCell *a, const ListCell *b)
 
static int append_startup_cost_compare (const ListCell *a, const ListCell *b)
 
static Listreparameterize_pathlist_by_child (PlannerInfo *root, List *pathlist, RelOptInfo *child_rel)
 
static bool pathlist_is_reparameterizable_by_child (List *pathlist, RelOptInfo *child_rel)
 
int compare_path_costs (Path *path1, Path *path2, CostSelector criterion)
 
int compare_fractional_path_costs (Path *path1, Path *path2, double fraction)
 
static PathCostComparison compare_path_costs_fuzzily (Path *path1, Path *path2, double fuzz_factor)
 
void set_cheapest (RelOptInfo *parent_rel)
 
void add_path (RelOptInfo *parent_rel, Path *new_path)
 
bool add_path_precheck (RelOptInfo *parent_rel, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
 
void add_partial_path (RelOptInfo *parent_rel, Path *new_path)
 
bool add_partial_path_precheck (RelOptInfo *parent_rel, int disabled_nodes, Cost total_cost, List *pathkeys)
 
Pathcreate_seqscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
 
Pathcreate_samplescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
IndexPathcreate_index_path (PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
 
BitmapHeapPathcreate_bitmap_heap_path (PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
 
BitmapAndPathcreate_bitmap_and_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
BitmapOrPathcreate_bitmap_or_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
TidPathcreate_tidscan_path (PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
 
TidRangePathcreate_tidrangescan_path (PlannerInfo *root, RelOptInfo *rel, List *tidrangequals, Relids required_outer, int parallel_workers)
 
AppendPathcreate_append_path (PlannerInfo *root, RelOptInfo *rel, AppendPathInput input, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *child_append_relid_sets, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath, bool enabled)
 
MemoizePathcreate_memoize_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, Cardinality est_calls)
 
GatherMergePathcreate_gather_merge_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *pathkeys, Relids required_outer, double *rows)
 
GatherPathcreate_gather_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
 
SubqueryScanPathcreate_subqueryscan_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
 
Pathcreate_functionscan_path (PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer)
 
Pathcreate_tablefuncscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_valuesscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_ctescan_path (PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer)
 
Pathcreate_namedtuplestorescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_resultscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_worktablescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
ForeignPathcreate_foreignscan_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
ForeignPathcreate_foreign_join_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
ForeignPathcreate_foreign_upper_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
Relids calc_nestloop_required_outer (Relids outerrelids, Relids outer_paramrels, Relids innerrelids, Relids inner_paramrels)
 
Relids calc_non_nestloop_required_outer (Path *outer_path, Path *inner_path)
 
NestPathcreate_nestloop_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer)
 
MergePathcreate_mergejoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer, List *mergeclauses, List *outersortkeys, List *innersortkeys, int outer_presorted_keys)
 
HashPathcreate_hashjoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, bool parallel_hash, List *restrict_clauses, Relids required_outer, List *hashclauses)
 
ProjectionPathcreate_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
Pathapply_projection_to_path (PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
 
ProjectSetPathcreate_set_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
IncrementalSortPathcreate_incremental_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
 
SortPathcreate_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
 
GroupPathcreate_group_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *groupClause, List *qual, double numGroups)
 
UniquePathcreate_unique_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
 
AggPathcreate_agg_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, AggStrategy aggstrategy, AggSplit aggsplit, List *groupClause, List *qual, const AggClauseCosts *aggcosts, double numGroups)
 
GroupingSetsPathcreate_groupingsets_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *having_qual, AggStrategy aggstrategy, List *rollups, const AggClauseCosts *agg_costs)
 
MinMaxAggPathcreate_minmaxagg_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *mmaggregates, List *quals)
 
WindowAggPathcreate_windowagg_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *windowFuncs, List *runCondition, WindowClause *winclause, List *qual, bool topwindow)
 
SetOpPathcreate_setop_path (PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, SetOpCmd cmd, SetOpStrategy strategy, List *groupList, double numGroups, double outputRows)
 
RecursiveUnionPathcreate_recursiveunion_path (PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
 
LockRowsPathcreate_lockrows_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *rowMarks, int epqParam)
 
ModifyTablePathcreate_modifytable_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, CmdType operation, bool canSetTag, Index nominalRelation, Index rootRelation, List *resultRelations, List *updateColnosLists, List *withCheckOptionLists, List *returningLists, List *rowMarks, OnConflictExpr *onconflict, List *mergeActionLists, List *mergeJoinConditions, int epqParam)
 
LimitPathcreate_limit_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, Node *limitOffset, Node *limitCount, LimitOption limitOption, int64 offset_est, int64 count_est)
 
void adjust_limit_rows_costs (double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
 
Pathreparameterize_path (PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
 
Pathreparameterize_path_by_child (PlannerInfo *root, Path *path, RelOptInfo *child_rel)
 
bool path_is_reparameterizable_by_child (Path *path, RelOptInfo *child_rel)
 

Macro Definition Documentation

◆ ADJUST_CHILD_ATTRS

#define ADJUST_CHILD_ATTRS (   node)
Value:
(Node *) (node), \
child_rel->top_parent))
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition appendinfo.c:596
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:4495

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

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

◆ 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:4466
#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 794 of file pathnode.c.

795{
796 bool accept_new = true; /* unless we find a superior old path */
797 int insert_at = 0; /* where to insert new item */
798 ListCell *p1;
799
800 /* Check for query cancel. */
802
803 /* Path to be added must be parallel safe. */
804 Assert(new_path->parallel_safe);
805
806 /* Relation should be OK for parallelism, too. */
807 Assert(parent_rel->consider_parallel);
808
809 /*
810 * As in add_path, throw out any paths which are dominated by the new
811 * path, but throw out the new path if some existing path dominates it.
812 */
813 foreach(p1, parent_rel->partial_pathlist)
814 {
815 Path *old_path = (Path *) lfirst(p1);
816 bool remove_old = false; /* unless new proves superior */
818
819 /* Compare pathkeys. */
820 keyscmp = compare_pathkeys(new_path->pathkeys, old_path->pathkeys);
821
822 /* Unless pathkeys are incompatible, keep just one of the two paths. */
824 {
825 if (unlikely(new_path->disabled_nodes != old_path->disabled_nodes))
826 {
827 if (new_path->disabled_nodes > old_path->disabled_nodes)
828 accept_new = false;
829 else
830 remove_old = true;
831 }
832 else if (new_path->total_cost > old_path->total_cost
834 {
835 /* New path costs more; keep it only if pathkeys are better. */
837 accept_new = false;
838 }
839 else if (old_path->total_cost > new_path->total_cost
841 {
842 /* Old path costs more; keep it only if pathkeys are better. */
844 remove_old = true;
845 }
846 else if (keyscmp == PATHKEYS_BETTER1)
847 {
848 /* Costs are about the same, new path has better pathkeys. */
849 remove_old = true;
850 }
851 else if (keyscmp == PATHKEYS_BETTER2)
852 {
853 /* Costs are about the same, old path has better pathkeys. */
854 accept_new = false;
855 }
856 else if (old_path->total_cost > new_path->total_cost * 1.0000000001)
857 {
858 /* Pathkeys are the same, and the old path costs more. */
859 remove_old = true;
860 }
861 else
862 {
863 /*
864 * Pathkeys are the same, and new path isn't materially
865 * cheaper.
866 */
867 accept_new = false;
868 }
869 }
870
871 /*
872 * Remove current element from partial_pathlist if dominated by new.
873 */
874 if (remove_old)
875 {
876 parent_rel->partial_pathlist =
877 foreach_delete_current(parent_rel->partial_pathlist, p1);
879 }
880 else
881 {
882 /*
883 * new belongs after this old path if it has more disabled nodes
884 * or if it has the same number of nodes but a greater total cost
885 */
886 if (new_path->disabled_nodes > old_path->disabled_nodes ||
887 (new_path->disabled_nodes == old_path->disabled_nodes &&
888 new_path->total_cost >= old_path->total_cost))
890 }
891
892 /*
893 * If we found an old path that dominates new_path, we can quit
894 * scanning the partial_pathlist; we will not add new_path, and we
895 * assume new_path cannot dominate any later path.
896 */
897 if (!accept_new)
898 break;
899 }
900
901 if (accept_new)
902 {
903 /* Accept the new path: insert it at proper place */
904 parent_rel->partial_pathlist =
905 list_insert_nth(parent_rel->partial_pathlist, insert_at, new_path);
906 }
907 else
908 {
909 /* Reject and recycle the new path */
911 }
912}
#define Assert(condition)
Definition c.h:885
#define unlikely(x)
Definition c.h:424
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 925 of file pathnode.c.

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

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

Referenced by try_partial_hashjoin_path(), try_partial_mergejoin_path(), and try_partial_nestloop_path().

◆ add_path()

void add_path ( RelOptInfo parent_rel,
Path new_path 
)

Definition at line 459 of file pathnode.c.

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

References BMS_EQUAL, BMS_SUBSET1, BMS_SUBSET2, bms_subset_compare(), CHECK_FOR_INTERRUPTS, compare_path_costs_fuzzily(), compare_pathkeys(), COSTS_BETTER1, COSTS_BETTER2, COSTS_DIFFERENT, COSTS_EQUAL, fb(), foreach_current_index, foreach_delete_current, IsA, lfirst, list_insert_nth(), NIL, PATH_REQ_OUTER, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, pfree(), and STD_FUZZ_FACTOR.

Referenced by add_foreign_final_paths(), add_foreign_grouping_paths(), add_foreign_ordered_paths(), add_paths_to_append_rel(), add_paths_to_grouping_rel(), add_paths_with_pathkeys_for_rel(), build_setop_child_paths(), BuildParameterizedTidPaths(), consider_groupingsets_paths(), create_degenerate_grouping_paths(), create_final_distinct_paths(), create_final_unique_paths(), create_index_paths(), create_one_window_path(), create_ordered_paths(), create_partial_grouping_paths(), create_tidscan_paths(), fileGetForeignPaths(), gather_grouping_paths(), generate_gather_paths(), generate_grouped_paths(), generate_nonunion_paths(), generate_orderedappend_paths(), generate_recursion_path(), generate_union_paths(), generate_useful_gather_paths(), get_index_paths(), grouping_planner(), mark_dummy_rel(), postgresGetForeignJoinPaths(), postgresGetForeignPaths(), preprocess_minmax_aggregates(), query_planner(), set_cte_pathlist(), set_dummy_rel_pathlist(), set_function_pathlist(), set_namedtuplestore_pathlist(), set_plain_rel_pathlist(), set_result_pathlist(), set_subquery_pathlist(), set_tablefunc_pathlist(), set_tablesample_rel_pathlist(), set_values_pathlist(), set_worktable_pathlist(), try_hashjoin_path(), try_mergejoin_path(), and try_nestloop_path().

◆ add_path_precheck()

bool add_path_precheck ( RelOptInfo parent_rel,
int  disabled_nodes,
Cost  startup_cost,
Cost  total_cost,
List pathkeys,
Relids  required_outer 
)

Definition at line 686 of file pathnode.c.

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

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

Referenced by add_partial_path_precheck(), try_hashjoin_path(), try_mergejoin_path(), and try_nestloop_path().

◆ adjust_limit_rows_costs()

void adjust_limit_rows_costs ( double rows,
Cost startup_cost,
Cost total_cost,
int64  offset_est,
int64  count_est 
)

Definition at line 3801 of file pathnode.c.

3806{
3807 double input_rows = *rows;
3808 Cost input_startup_cost = *startup_cost;
3809 Cost input_total_cost = *total_cost;
3810
3811 if (offset_est != 0)
3812 {
3813 double offset_rows;
3814
3815 if (offset_est > 0)
3816 offset_rows = (double) offset_est;
3817 else
3819 if (offset_rows > *rows)
3820 offset_rows = *rows;
3821 if (input_rows > 0)
3822 *startup_cost +=
3825 *rows -= offset_rows;
3826 if (*rows < 1)
3827 *rows = 1;
3828 }
3829
3830 if (count_est != 0)
3831 {
3832 double count_rows;
3833
3834 if (count_est > 0)
3835 count_rows = (double) count_est;
3836 else
3838 if (count_rows > *rows)
3839 count_rows = *rows;
3840 if (input_rows > 0)
3841 *total_cost = *startup_cost +
3844 *rows = count_rows;
3845 if (*rows < 1)
3846 *rows = 1;
3847 }
3848}
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 1459 of file pathnode.c.

1460{
1461 Path *path1 = (Path *) lfirst(a);
1462 Path *path2 = (Path *) lfirst(b);
1463 int cmp;
1464
1466 if (cmp != 0)
1467 return -cmp;
1468 return bms_compare(path1->parent->relids, path2->parent->relids);
1469}
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 1437 of file pathnode.c.

1438{
1439 Path *path1 = (Path *) lfirst(a);
1440 Path *path2 = (Path *) lfirst(b);
1441 int cmp;
1442
1444 if (cmp != 0)
1445 return -cmp;
1446 return bms_compare(path1->parent->relids, path2->parent->relids);
1447}
@ 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 2649 of file pathnode.c.

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

References PathTarget::cost, create_projection_path(), PathTarget::exprs, fb(), is_parallel_safe(), is_projection_capable_path(), IsA, Path::parallel_safe, QualCost::per_tuple, root, Path::rows, QualCost::startup, Path::startup_cost, and Path::total_cost.

Referenced by adjust_paths_for_srfs(), build_minmax_path(), create_ordered_paths(), and recurse_set_operations().

◆ calc_nestloop_required_outer()

Relids calc_nestloop_required_outer ( Relids  outerrelids,
Relids  outer_paramrels,
Relids  innerrelids,
Relids  inner_paramrels 
)

Definition at line 2230 of file pathnode.c.

2234{
2236
2237 /* inner_path can require rels from outer path, but not vice versa */
2239 /* easy case if inner path is not parameterized */
2240 if (!inner_paramrels)
2241 return bms_copy(outer_paramrels);
2242 /* else, form the union ... */
2244 /* ... and remove any mention of now-satisfied outer rels */
2246 outerrelids);
2247 return required_outer;
2248}
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1145
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:575
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 2257 of file pathnode.c.

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

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

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

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

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

◆ create_append_path()

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

Definition at line 1305 of file pathnode.c.

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

References append_startup_cost_compare(), append_total_cost_compare(), Assert, bms_equal(), RelOptInfo::consider_parallel, cost_append(), fb(), get_appendrel_parampathinfo(), get_baserel_parampathinfo(), input, lfirst, linitial, list_concat(), list_length(), list_sort(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, PATH_REQ_OUTER, Path::pathkeys, RelOptInfo::relids, RELOPT_BASEREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, root, Path::rows, Path::startup_cost, subpath(), and Path::total_cost.

Referenced by add_paths_to_append_rel(), create_degenerate_grouping_paths(), generate_nonunion_paths(), generate_orderedappend_paths(), generate_union_paths(), mark_dummy_rel(), reparameterize_path(), and set_dummy_rel_pathlist().

◆ create_bitmap_and_path()

BitmapAndPath * create_bitmap_and_path ( PlannerInfo root,
RelOptInfo rel,
List bitmapquals 
)

Definition at line 1135 of file pathnode.c.

1138{
1141 ListCell *lc;
1142
1143 pathnode->path.pathtype = T_BitmapAnd;
1144 pathnode->path.parent = rel;
1145 pathnode->path.pathtarget = rel->reltarget;
1146
1147 /*
1148 * Identify the required outer rels as the union of what the child paths
1149 * depend on. (Alternatively, we could insist that the caller pass this
1150 * in, but it's more convenient and reliable to compute it here.)
1151 */
1152 foreach(lc, bitmapquals)
1153 {
1154 Path *bitmapqual = (Path *) lfirst(lc);
1155
1157 PATH_REQ_OUTER(bitmapqual));
1158 }
1159 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1161
1162 /*
1163 * Currently, a BitmapHeapPath, BitmapAndPath, or BitmapOrPath will be
1164 * parallel-safe if and only if rel->consider_parallel is set. So, we can
1165 * set the flag for this path based only on the relation-level flag,
1166 * without actually iterating over the list of children.
1167 */
1168 pathnode->path.parallel_aware = false;
1169 pathnode->path.parallel_safe = rel->consider_parallel;
1170 pathnode->path.parallel_workers = 0;
1171
1172 pathnode->path.pathkeys = NIL; /* always unordered */
1173
1174 pathnode->bitmapquals = bitmapquals;
1175
1176 /* this sets bitmapselectivity as well as the regular cost fields: */
1178
1179 return pathnode;
1180}
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:901
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 1102 of file pathnode.c.

1108{
1110
1111 pathnode->path.pathtype = T_BitmapHeapScan;
1112 pathnode->path.parent = rel;
1113 pathnode->path.pathtarget = rel->reltarget;
1114 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1116 pathnode->path.parallel_aware = (parallel_degree > 0);
1117 pathnode->path.parallel_safe = rel->consider_parallel;
1118 pathnode->path.parallel_workers = parallel_degree;
1119 pathnode->path.pathkeys = NIL; /* always unordered */
1120
1121 pathnode->bitmapqual = bitmapqual;
1122
1123 cost_bitmap_heap_scan(&pathnode->path, root, rel,
1124 pathnode->path.param_info,
1125 bitmapqual, loop_count);
1126
1127 return pathnode;
1128}
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 1187 of file pathnode.c.

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

1972{
1974
1975 pathnode->pathtype = T_CteScan;
1976 pathnode->parent = rel;
1977 pathnode->pathtarget = rel->reltarget;
1978 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1980 pathnode->parallel_aware = false;
1981 pathnode->parallel_safe = rel->consider_parallel;
1982 pathnode->parallel_workers = 0;
1983 pathnode->pathkeys = pathkeys;
1984
1985 cost_ctescan(pathnode, root, rel, pathnode->param_info);
1986
1987 return pathnode;
1988}
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 2129 of file pathnode.c.

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

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

Referenced by add_paths_with_pathkeys_for_rel(), and postgresGetForeignJoinPaths().

◆ create_foreign_upper_path()

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

Definition at line 2183 of file pathnode.c.

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

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

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

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

Referenced by add_paths_with_pathkeys_for_rel(), fileGetForeignPaths(), and postgresGetForeignPaths().

◆ create_functionscan_path()

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

Definition at line 1892 of file pathnode.c.

1894{
1896
1897 pathnode->pathtype = T_FunctionScan;
1898 pathnode->parent = rel;
1899 pathnode->pathtarget = rel->reltarget;
1900 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1902 pathnode->parallel_aware = false;
1903 pathnode->parallel_safe = rel->consider_parallel;
1904 pathnode->parallel_workers = 0;
1905 pathnode->pathkeys = pathkeys;
1906
1907 cost_functionscan(pathnode, root, rel, pathnode->param_info);
1908
1909 return pathnode;
1910}
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 1766 of file pathnode.c.

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

1820{
1822
1823 Assert(subpath->parallel_safe);
1824
1825 pathnode->path.pathtype = T_Gather;
1826 pathnode->path.parent = rel;
1827 pathnode->path.pathtarget = target;
1828 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1830 pathnode->path.parallel_aware = false;
1831 pathnode->path.parallel_safe = false;
1832 pathnode->path.parallel_workers = 0;
1833 pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1834
1835 pathnode->subpath = subpath;
1836 pathnode->num_workers = subpath->parallel_workers;
1837 pathnode->single_copy = false;
1838
1839 if (pathnode->num_workers == 0)
1840 {
1841 pathnode->path.pathkeys = subpath->pathkeys;
1842 pathnode->num_workers = 1;
1843 pathnode->single_copy = true;
1844 }
1845
1846 cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1847
1848 return pathnode;
1849}
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 2901 of file pathnode.c.

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

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

Referenced by add_paths_to_grouping_rel(), and create_partial_grouping_paths().

◆ create_group_result_path()

GroupResultPath * create_group_result_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
List havingqual 
)

Definition at line 1617 of file pathnode.c.

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

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

Referenced by create_degenerate_grouping_paths(), and query_planner().

◆ create_groupingsets_path()

GroupingSetsPath * create_groupingsets_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List having_qual,
AggStrategy  aggstrategy,
List rollups,
const AggClauseCosts agg_costs 
)

Definition at line 3092 of file pathnode.c.

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

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

References RelOptInfo::consider_parallel, fb(), final_cost_hashjoin(), get_joinrel_parampathinfo(), JoinPathExtraData::inner_unique, makeNode, NIL, RelOptInfo::reltarget, root, and JoinPathExtraData::sjinfo.

Referenced by try_hashjoin_path(), and try_partial_hashjoin_path().

◆ create_incremental_sort_path()

IncrementalSortPath * create_incremental_sort_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List pathkeys,
int  presorted_keys,
double  limit_tuples 
)

Definition at line 2808 of file pathnode.c.

2814{
2816 SortPath *pathnode = &sort->spath;
2817
2819 pathnode->path.parent = rel;
2820 /* Sort doesn't project, so use source path's pathtarget */
2821 pathnode->path.pathtarget = subpath->pathtarget;
2822 pathnode->path.param_info = subpath->param_info;
2823 pathnode->path.parallel_aware = false;
2824 pathnode->path.parallel_safe = rel->consider_parallel &&
2825 subpath->parallel_safe;
2826 pathnode->path.parallel_workers = subpath->parallel_workers;
2827 pathnode->path.pathkeys = pathkeys;
2828
2829 pathnode->subpath = subpath;
2830
2832 root, pathkeys, presorted_keys,
2833 subpath->disabled_nodes,
2834 subpath->startup_cost,
2835 subpath->total_cost,
2836 subpath->rows,
2837 subpath->pathtarget->width,
2838 0.0, /* XXX comparison_cost shouldn't be 0? */
2839 work_mem, limit_tuples);
2840
2841 sort->nPresortedCols = presorted_keys;
2842
2843 return sort;
2844}
Datum sort(PG_FUNCTION_ARGS)
Definition _int_op.c:198
void cost_incremental_sort(Path *path, PlannerInfo *root, List *pathkeys, int presorted_keys, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double input_tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition costsize.c:2052
NodeTag pathtype
Definition pathnodes.h:1957
Path path
Definition pathnodes.h:2523

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

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

◆ create_index_path()

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

Definition at line 1053 of file pathnode.c.

1064{
1066 RelOptInfo *rel = index->rel;
1067
1068 pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
1069 pathnode->path.parent = rel;
1070 pathnode->path.pathtarget = rel->reltarget;
1071 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1073 pathnode->path.parallel_aware = false;
1074 pathnode->path.parallel_safe = rel->consider_parallel;
1075 pathnode->path.parallel_workers = 0;
1076 pathnode->path.pathkeys = pathkeys;
1077
1078 pathnode->indexinfo = index;
1079 pathnode->indexclauses = indexclauses;
1080 pathnode->indexorderbys = indexorderbys;
1081 pathnode->indexorderbycols = indexorderbycols;
1082 pathnode->indexscandir = indexscandir;
1083
1085
1086 return pathnode;
1087}
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 3745 of file pathnode.c.

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

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

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

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

Referenced by grouping_planner().

◆ create_material_path()

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

Definition at line 1665 of file pathnode.c.

1666{
1668
1669 Assert(subpath->parent == rel);
1670
1671 pathnode->path.pathtype = T_Material;
1672 pathnode->path.parent = rel;
1673 pathnode->path.pathtarget = rel->reltarget;
1674 pathnode->path.param_info = subpath->param_info;
1675 pathnode->path.parallel_aware = false;
1676 pathnode->path.parallel_safe = rel->consider_parallel &&
1677 subpath->parallel_safe;
1678 pathnode->path.parallel_workers = subpath->parallel_workers;
1679 pathnode->path.pathkeys = subpath->pathkeys;
1680
1681 pathnode->subpath = subpath;
1682
1683 cost_material(&pathnode->path,
1684 enabled,
1685 subpath->disabled_nodes,
1686 subpath->startup_cost,
1687 subpath->total_cost,
1688 subpath->rows,
1689 subpath->pathtarget->width);
1690
1691 return pathnode;
1692}
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 1699 of file pathnode.c.

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

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

Referenced by get_memoize_path(), and reparameterize_path().

◆ create_merge_append_path()

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

Definition at line 1477 of file pathnode.c.

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

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

References RelOptInfo::consider_parallel, fb(), final_cost_mergejoin(), get_joinrel_parampathinfo(), JoinPathExtraData::inner_unique, makeNode, RelOptInfo::reltarget, root, and JoinPathExtraData::sjinfo.

Referenced by try_mergejoin_path(), and try_partial_mergejoin_path().

◆ create_minmaxagg_path()

MinMaxAggPath * create_minmaxagg_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
List mmaggregates,
List quals 
)

Definition at line 3255 of file pathnode.c.

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

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

Referenced by preprocess_minmax_aggregates().

◆ create_modifytable_path()

ModifyTablePath * create_modifytable_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
CmdType  operation,
bool  canSetTag,
Index  nominalRelation,
Index  rootRelation,
List resultRelations,
List updateColnosLists,
List withCheckOptionLists,
List returningLists,
List rowMarks,
OnConflictExpr onconflict,
List mergeActionLists,
List mergeJoinConditions,
int  epqParam 
)

Definition at line 3645 of file pathnode.c.

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

1998{
2000
2001 pathnode->pathtype = T_NamedTuplestoreScan;
2002 pathnode->parent = rel;
2003 pathnode->pathtarget = rel->reltarget;
2004 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2006 pathnode->parallel_aware = false;
2007 pathnode->parallel_safe = rel->consider_parallel;
2008 pathnode->parallel_workers = 0;
2009 pathnode->pathkeys = NIL; /* result is always unordered */
2010
2011 cost_namedtuplestorescan(pathnode, root, rel, pathnode->param_info);
2012
2013 return pathnode;
2014}
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 2309 of file pathnode.c.

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

References bms_is_member(), bms_overlap(), RelOptInfo::consider_parallel, fb(), final_cost_nestloop(), get_joinrel_parampathinfo(), get_param_path_clause_serials(), JoinPathExtraData::inner_unique, lappend(), lfirst, makeNode, NIL, PATH_REQ_OUTER, RelOptInfo::reltarget, RestrictInfo::rinfo_serial, root, and JoinPathExtraData::sjinfo.

Referenced by try_nestloop_path(), and try_partial_nestloop_path().

◆ create_projection_path()

ProjectionPath * create_projection_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target 
)

Definition at line 2540 of file pathnode.c.

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

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

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

Referenced by generate_recursion_path().

◆ create_resultscan_path()

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

Definition at line 2022 of file pathnode.c.

2024{
2026
2027 pathnode->pathtype = T_Result;
2028 pathnode->parent = rel;
2029 pathnode->pathtarget = rel->reltarget;
2030 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2032 pathnode->parallel_aware = false;
2033 pathnode->parallel_safe = rel->consider_parallel;
2034 pathnode->parallel_workers = 0;
2035 pathnode->pathkeys = NIL; /* result is always unordered */
2036
2037 cost_resultscan(pathnode, root, rel, pathnode->param_info);
2038
2039 return pathnode;
2040}
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 1012 of file pathnode.c.

1013{
1015
1016 pathnode->pathtype = T_SampleScan;
1017 pathnode->parent = rel;
1018 pathnode->pathtarget = rel->reltarget;
1019 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1021 pathnode->parallel_aware = false;
1022 pathnode->parallel_safe = rel->consider_parallel;
1023 pathnode->parallel_workers = 0;
1024 pathnode->pathkeys = NIL; /* samplescan has unordered result */
1025
1026 cost_samplescan(pathnode, root, rel, pathnode->param_info);
1027
1028 return pathnode;
1029}
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 987 of file pathnode.c.

989{
991
992 pathnode->pathtype = T_SeqScan;
993 pathnode->parent = rel;
994 pathnode->pathtarget = rel->reltarget;
995 pathnode->param_info = get_baserel_parampathinfo(root, rel,
997 pathnode->parallel_aware = (parallel_workers > 0);
998 pathnode->parallel_safe = rel->consider_parallel;
999 pathnode->parallel_workers = parallel_workers;
1000 pathnode->pathkeys = NIL; /* seqscan has unordered result */
1001
1002 cost_seqscan(pathnode, root, rel, pathnode->param_info);
1003
1004 return pathnode;
1005}
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 2738 of file pathnode.c.

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

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

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

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

1865{
1867
1868 pathnode->path.pathtype = T_SubqueryScan;
1869 pathnode->path.parent = rel;
1870 pathnode->path.pathtarget = rel->reltarget;
1871 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1873 pathnode->path.parallel_aware = false;
1874 pathnode->path.parallel_safe = rel->consider_parallel &&
1875 subpath->parallel_safe;
1876 pathnode->path.parallel_workers = subpath->parallel_workers;
1877 pathnode->path.pathkeys = pathkeys;
1878 pathnode->subpath = subpath;
1879
1880 cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
1882
1883 return pathnode;
1884}
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 1918 of file pathnode.c.

1920{
1922
1923 pathnode->pathtype = T_TableFuncScan;
1924 pathnode->parent = rel;
1925 pathnode->pathtarget = rel->reltarget;
1926 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1928 pathnode->parallel_aware = false;
1929 pathnode->parallel_safe = rel->consider_parallel;
1930 pathnode->parallel_workers = 0;
1931 pathnode->pathkeys = NIL; /* result is always unordered */
1932
1933 cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
1934
1935 return pathnode;
1936}
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 1268 of file pathnode.c.

1271{
1273
1274 pathnode->path.pathtype = T_TidRangeScan;
1275 pathnode->path.parent = rel;
1276 pathnode->path.pathtarget = rel->reltarget;
1277 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1279 pathnode->path.parallel_aware = (parallel_workers > 0);
1280 pathnode->path.parallel_safe = rel->consider_parallel;
1281 pathnode->path.parallel_workers = parallel_workers;
1282 pathnode->path.pathkeys = NIL; /* always unordered */
1283
1284 pathnode->tidrangequals = tidrangequals;
1285
1286 cost_tidrangescan(&pathnode->path, root, rel, tidrangequals,
1287 pathnode->path.param_info);
1288
1289 return pathnode;
1290}
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 1239 of file pathnode.c.

1241{
1243
1244 pathnode->path.pathtype = T_TidScan;
1245 pathnode->path.parent = rel;
1246 pathnode->path.pathtarget = rel->reltarget;
1247 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1249 pathnode->path.parallel_aware = false;
1250 pathnode->path.parallel_safe = rel->consider_parallel;
1251 pathnode->path.parallel_workers = 0;
1252 pathnode->path.pathkeys = NIL; /* always unordered */
1253
1254 pathnode->tidquals = tidquals;
1255
1256 cost_tidscan(&pathnode->path, root, rel, tidquals,
1257 pathnode->path.param_info);
1258
1259 return pathnode;
1260}
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 2958 of file pathnode.c.

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

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

1946{
1948
1949 pathnode->pathtype = T_ValuesScan;
1950 pathnode->parent = rel;
1951 pathnode->pathtarget = rel->reltarget;
1952 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1954 pathnode->parallel_aware = false;
1955 pathnode->parallel_safe = rel->consider_parallel;
1956 pathnode->parallel_workers = 0;
1957 pathnode->pathkeys = NIL; /* result is always unordered */
1958
1959 cost_valuesscan(pathnode, root, rel, pathnode->param_info);
1960
1961 return pathnode;
1962}
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 3346 of file pathnode.c.

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

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

Referenced by create_one_window_path().

◆ create_worktablescan_path()

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

Definition at line 2048 of file pathnode.c.

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

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

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

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

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

◆ pathlist_is_reparameterizable_by_child()

static bool pathlist_is_reparameterizable_by_child ( List pathlist,
RelOptInfo child_rel 
)
static

Definition at line 4495 of file pathnode.c.

4496{
4497 ListCell *lc;
4498
4499 foreach(lc, pathlist)
4500 {
4501 Path *path = (Path *) lfirst(lc);
4502
4504 return false;
4505 }
4506
4507 return true;
4508}

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

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

References bms_is_subset(), cost_index(), create_append_path(), create_bitmap_heap_path(), create_material_path(), create_memoize_path(), create_resultscan_path(), create_samplescan_path(), create_seqscan_path(), create_subqueryscan_path(), Path::disabled_nodes, fb(), get_baserel_parampathinfo(), i, IsA, lappend(), lfirst, makeNode, SubqueryScanPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, reparameterize_path(), root, subpath(), SubqueryScanPath::subpath, and Path::total_cost.

Referenced by get_cheapest_parameterized_child_path(), and reparameterize_path().

◆ reparameterize_path_by_child()

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

Definition at line 4039 of file pathnode.c.

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

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

Referenced by create_nestloop_plan(), and reparameterize_pathlist_by_child().

◆ reparameterize_pathlist_by_child()

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

Definition at line 4466 of file pathnode.c.

4469{
4470 ListCell *lc;
4471 List *result = NIL;
4472
4473 foreach(lc, pathlist)
4474 {
4476 child_rel);
4477
4478 if (path == NULL)
4479 {
4480 list_free(result);
4481 return NIL;
4482 }
4483
4484 result = lappend(result, path);
4485 }
4486
4487 return result;
4488}
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().