PostgreSQL Source Code git master
pathnode.c File Reference
#include "postgres.h"
#include <math.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)
 
AppendPathcreate_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *partial_subpaths, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath)
 
MemoizePathcreate_memoize_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, 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, \
child_rel->top_parent))
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition: appendinfo.c:592
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 { \
if (!pathlist_is_reparameterizable_by_child(pathlist, child_rel)) \
return false; \
} while(0)
static bool pathlist_is_reparameterizable_by_child(List *pathlist, RelOptInfo *child_rel)
Definition: pathnode.c:4475

◆ REJECT_IF_PATH_NOT_REPARAMETERIZABLE

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

◆ REPARAMETERIZE_CHILD_PATH

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

◆ REPARAMETERIZE_CHILD_PATH_LIST

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

◆ STD_FUZZ_FACTOR

#define STD_FUZZ_FACTOR   1.01

Definition at line 49 of file pathnode.c.

Enumeration Type Documentation

◆ PathCostComparison

Enumerator
COSTS_EQUAL 
COSTS_BETTER1 
COSTS_BETTER2 
COSTS_DIFFERENT 

Definition at line 36 of file pathnode.c.

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

Function Documentation

◆ add_partial_path()

void add_partial_path ( RelOptInfo parent_rel,
Path new_path 
)

Definition at line 795 of file pathnode.c.

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

References Assert(), CHECK_FOR_INTERRUPTS, compare_pathkeys(), RelOptInfo::consider_parallel, Path::disabled_nodes, foreach_current_index, foreach_delete_current, lfirst, list_insert_nth(), Path::parallel_safe, RelOptInfo::partial_pathlist, Path::pathkeys, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, pfree(), STD_FUZZ_FACTOR, Path::total_cost, 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(), 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 921 of file pathnode.c.

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

References add_path_precheck(), compare_pathkeys(), lfirst, RelOptInfo::partial_pathlist, Path::pathkeys, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, STD_FUZZ_FACTOR, and Path::total_cost.

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

◆ add_path()

void add_path ( RelOptInfo parent_rel,
Path new_path 
)

Definition at line 461 of file pathnode.c.

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

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, Path::disabled_nodes, foreach_current_index, foreach_delete_current, IsA, lfirst, list_insert_nth(), NIL, Path::parallel_safe, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, RelOptInfo::pathlist, pfree(), Path::rows, STD_FUZZ_FACTOR, and Path::total_cost.

Referenced by add_foreign_final_paths(), add_foreign_grouping_paths(), add_foreign_ordered_paths(), add_paths_to_append_rel(), add_paths_to_grouping_rel(), add_paths_with_pathkeys_for_rel(), 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 688 of file pathnode.c.

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

References bms_equal(), compare_pathkeys(), RelOptInfo::consider_param_startup, RelOptInfo::consider_startup, Path::disabled_nodes, lfirst, NIL, PATH_REQ_OUTER, Path::pathkeys, PATHKEYS_BETTER2, PATHKEYS_EQUAL, RelOptInfo::pathlist, Path::startup_cost, 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 3785 of file pathnode.c.

3790{
3791 double input_rows = *rows;
3792 Cost input_startup_cost = *startup_cost;
3793 Cost input_total_cost = *total_cost;
3794
3795 if (offset_est != 0)
3796 {
3797 double offset_rows;
3798
3799 if (offset_est > 0)
3800 offset_rows = (double) offset_est;
3801 else
3802 offset_rows = clamp_row_est(input_rows * 0.10);
3803 if (offset_rows > *rows)
3804 offset_rows = *rows;
3805 if (input_rows > 0)
3806 *startup_cost +=
3807 (input_total_cost - input_startup_cost)
3808 * offset_rows / input_rows;
3809 *rows -= offset_rows;
3810 if (*rows < 1)
3811 *rows = 1;
3812 }
3813
3814 if (count_est != 0)
3815 {
3816 double count_rows;
3817
3818 if (count_est > 0)
3819 count_rows = (double) count_est;
3820 else
3821 count_rows = clamp_row_est(input_rows * 0.10);
3822 if (count_rows > *rows)
3823 count_rows = *rows;
3824 if (input_rows > 0)
3825 *total_cost = *startup_cost +
3826 (input_total_cost - input_startup_cost)
3827 * count_rows / input_rows;
3828 *rows = count_rows;
3829 if (*rows < 1)
3830 *rows = 1;
3831 }
3832}
double clamp_row_est(double nrows)
Definition: costsize.c:213
double Cost
Definition: nodes.h:261

References clamp_row_est().

Referenced by create_limit_path(), and estimate_path_cost_size().

◆ append_startup_cost_compare()

static int append_startup_cost_compare ( const ListCell a,
const ListCell b 
)
static

Definition at line 1453 of file pathnode.c.

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

References a, b, bms_compare(), cmp(), compare_path_costs(), lfirst, and STARTUP_COST.

Referenced by create_append_path().

◆ append_total_cost_compare()

static int append_total_cost_compare ( const ListCell a,
const ListCell b 
)
static

Definition at line 1431 of file pathnode.c.

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

References a, b, bms_compare(), cmp(), compare_path_costs(), lfirst, and TOTAL_COST.

Referenced by create_append_path().

◆ apply_projection_to_path()

Path * apply_projection_to_path ( PlannerInfo root,
RelOptInfo rel,
Path path,
PathTarget target 
)

Definition at line 2633 of file pathnode.c.

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

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

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

◆ calc_nestloop_required_outer()

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

Definition at line 2214 of file pathnode.c.

2218{
2219 Relids required_outer;
2220
2221 /* inner_path can require rels from outer path, but not vice versa */
2222 Assert(!bms_overlap(outer_paramrels, innerrelids));
2223 /* easy case if inner path is not parameterized */
2224 if (!inner_paramrels)
2225 return bms_copy(outer_paramrels);
2226 /* else, form the union ... */
2227 required_outer = bms_union(outer_paramrels, inner_paramrels);
2228 /* ... and remove any mention of now-satisfied outer rels */
2229 required_outer = bms_del_members(required_outer,
2230 outerrelids);
2231 return required_outer;
2232}
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1161
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:582
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122

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

Referenced by try_nestloop_path().

◆ calc_non_nestloop_required_outer()

Relids calc_non_nestloop_required_outer ( Path outer_path,
Path inner_path 
)

Definition at line 2241 of file pathnode.c.

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

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

Referenced by try_hashjoin_path(), and try_mergejoin_path().

◆ compare_fractional_path_costs()

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

Definition at line 125 of file pathnode.c.

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

References compare_path_costs(), Path::disabled_nodes, Path::startup_cost, TOTAL_COST, Path::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 70 of file pathnode.c.

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

References Path::disabled_nodes, STARTUP_COST, Path::startup_cost, Path::total_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 183 of file pathnode.c.

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

References CONSIDER_PATH_STARTUP_COST, COSTS_BETTER1, COSTS_BETTER2, COSTS_DIFFERENT, COSTS_EQUAL, Path::disabled_nodes, Path::startup_cost, Path::total_cost, 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 2994 of file pathnode.c.

3004{
3005 AggPath *pathnode = makeNode(AggPath);
3006
3007 pathnode->path.pathtype = T_Agg;
3008 pathnode->path.parent = rel;
3009 pathnode->path.pathtarget = target;
3010 pathnode->path.param_info = subpath->param_info;
3011 pathnode->path.parallel_aware = false;
3012 pathnode->path.parallel_safe = rel->consider_parallel &&
3013 subpath->parallel_safe;
3014 pathnode->path.parallel_workers = subpath->parallel_workers;
3015
3016 if (aggstrategy == AGG_SORTED)
3017 {
3018 /*
3019 * Attempt to preserve the order of the subpath. Additional pathkeys
3020 * may have been added in adjust_group_pathkeys_for_groupagg() to
3021 * support ORDER BY / DISTINCT aggregates. Pathkeys added there
3022 * belong to columns within the aggregate function, so we must strip
3023 * these additional pathkeys off as those columns are unavailable
3024 * above the aggregate node.
3025 */
3026 if (list_length(subpath->pathkeys) > root->num_groupby_pathkeys)
3027 pathnode->path.pathkeys = list_copy_head(subpath->pathkeys,
3028 root->num_groupby_pathkeys);
3029 else
3030 pathnode->path.pathkeys = subpath->pathkeys; /* preserves order */
3031 }
3032 else
3033 pathnode->path.pathkeys = NIL; /* output is unordered */
3034
3035 pathnode->subpath = subpath;
3036
3037 pathnode->aggstrategy = aggstrategy;
3038 pathnode->aggsplit = aggsplit;
3039 pathnode->numGroups = numGroups;
3040 pathnode->transitionSpace = aggcosts ? aggcosts->transitionSpace : 0;
3041 pathnode->groupClause = groupClause;
3042 pathnode->qual = qual;
3043
3044 cost_agg(&pathnode->path, root,
3045 aggstrategy, aggcosts,
3046 list_length(groupClause), numGroups,
3047 qual,
3048 subpath->disabled_nodes,
3049 subpath->startup_cost, subpath->total_cost,
3050 subpath->rows, subpath->pathtarget->width);
3051
3052 /* add tlist eval cost for each output row */
3053 pathnode->path.startup_cost += target->cost.startup;
3054 pathnode->path.total_cost += target->cost.startup +
3055 target->cost.per_tuple * pathnode->path.rows;
3056
3057 return pathnode;
3058}
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:2688
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
Size transitionSpace
Definition: pathnodes.h:62
Path * subpath
Definition: pathnodes.h:2483
Cardinality numGroups
Definition: pathnodes.h:2486
AggSplit aggsplit
Definition: pathnodes.h:2485
List * groupClause
Definition: pathnodes.h:2488
uint64 transitionSpace
Definition: pathnodes.h:2487
AggStrategy aggstrategy
Definition: pathnodes.h:2484
Path path
Definition: pathnodes.h:2482
List * qual
Definition: pathnodes.h:2489
NodeTag pathtype
Definition: pathnodes.h:1872
int parallel_workers
Definition: pathnodes.h:1903
bool parallel_aware
Definition: pathnodes.h:1899

References AGG_SORTED, AggPath::aggsplit, AggPath::aggstrategy, RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), AggPath::groupClause, list_copy_head(), list_length(), makeNode, NIL, AggPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, AggPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, AggPath::qual, root, Path::rows, QualCost::startup, Path::startup_cost, subpath(), AggPath::subpath, Path::total_cost, AggClauseCosts::transitionSpace, and AggPath::transitionSpace.

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

◆ create_append_path()

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

Definition at line 1300 of file pathnode.c.

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

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

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

◆ create_bitmap_and_path()

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

Definition at line 1131 of file pathnode.c.

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

References BitmapAndPath::bitmapquals, bms_add_members(), RelOptInfo::consider_parallel, cost_bitmap_and_node(), get_baserel_parampathinfo(), lfirst, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, BitmapAndPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, 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 1098 of file pathnode.c.

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

References BitmapHeapPath::bitmapqual, RelOptInfo::consider_parallel, cost_bitmap_heap_scan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, BitmapHeapPath::path, Path::pathkeys, Path::pathtype, 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 1183 of file pathnode.c.

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

References BitmapOrPath::bitmapquals, bms_add_members(), RelOptInfo::consider_parallel, cost_bitmap_or_node(), get_baserel_parampathinfo(), lfirst, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, BitmapOrPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, 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 1954 of file pathnode.c.

1956{
1957 Path *pathnode = makeNode(Path);
1958
1959 pathnode->pathtype = T_CteScan;
1960 pathnode->parent = rel;
1961 pathnode->pathtarget = rel->reltarget;
1962 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1963 required_outer);
1964 pathnode->parallel_aware = false;
1965 pathnode->parallel_safe = rel->consider_parallel;
1966 pathnode->parallel_workers = 0;
1967 pathnode->pathkeys = pathkeys;
1968
1969 cost_ctescan(pathnode, root, rel, pathnode->param_info);
1970
1971 return pathnode;
1972}
void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1682

References RelOptInfo::consider_parallel, cost_ctescan(), get_baserel_parampathinfo(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::pathkeys, Path::pathtype, 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 2113 of file pathnode.c.

2122{
2123 ForeignPath *pathnode = makeNode(ForeignPath);
2124
2125 /*
2126 * We should use get_joinrel_parampathinfo to handle parameterized paths,
2127 * but the API of this function doesn't support it, and existing
2128 * extensions aren't yet trying to build such paths anyway. For the
2129 * moment just throw an error if someone tries it; eventually we should
2130 * revisit this.
2131 */
2132 if (!bms_is_empty(required_outer) || !bms_is_empty(rel->lateral_relids))
2133 elog(ERROR, "parameterized foreign joins are not supported yet");
2134
2135 pathnode->path.pathtype = T_ForeignScan;
2136 pathnode->path.parent = rel;
2137 pathnode->path.pathtarget = target ? target : rel->reltarget;
2138 pathnode->path.param_info = NULL; /* XXX see above */
2139 pathnode->path.parallel_aware = false;
2140 pathnode->path.parallel_safe = rel->consider_parallel;
2141 pathnode->path.parallel_workers = 0;
2142 pathnode->path.rows = rows;
2143 pathnode->path.disabled_nodes = disabled_nodes;
2144 pathnode->path.startup_cost = startup_cost;
2145 pathnode->path.total_cost = total_cost;
2146 pathnode->path.pathkeys = pathkeys;
2147
2148 pathnode->fdw_outerpath = fdw_outerpath;
2149 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2150 pathnode->fdw_private = fdw_private;
2151
2152 return pathnode;
2153}
#define bms_is_empty(a)
Definition: bitmapset.h:118
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
Path * fdw_outerpath
Definition: pathnodes.h:2117
List * fdw_restrictinfo
Definition: pathnodes.h:2118
List * fdw_private
Definition: pathnodes.h:2119
Relids lateral_relids
Definition: pathnodes.h:968

References bms_is_empty, RelOptInfo::consider_parallel, Path::disabled_nodes, elog, ERROR, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, ForeignPath::fdw_restrictinfo, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ForeignPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, and Path::total_cost.

Referenced by add_paths_with_pathkeys_for_rel(), and postgresGetForeignJoinPaths().

◆ create_foreign_upper_path()

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

Definition at line 2167 of file pathnode.c.

2175{
2176 ForeignPath *pathnode = makeNode(ForeignPath);
2177
2178 /*
2179 * Upper relations should never have any lateral references, since joining
2180 * is complete.
2181 */
2183
2184 pathnode->path.pathtype = T_ForeignScan;
2185 pathnode->path.parent = rel;
2186 pathnode->path.pathtarget = target ? target : rel->reltarget;
2187 pathnode->path.param_info = NULL;
2188 pathnode->path.parallel_aware = false;
2189 pathnode->path.parallel_safe = rel->consider_parallel;
2190 pathnode->path.parallel_workers = 0;
2191 pathnode->path.rows = rows;
2192 pathnode->path.disabled_nodes = disabled_nodes;
2193 pathnode->path.startup_cost = startup_cost;
2194 pathnode->path.total_cost = total_cost;
2195 pathnode->path.pathkeys = pathkeys;
2196
2197 pathnode->fdw_outerpath = fdw_outerpath;
2198 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2199 pathnode->fdw_private = fdw_private;
2200
2201 return pathnode;
2202}

References Assert(), bms_is_empty, RelOptInfo::consider_parallel, Path::disabled_nodes, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, ForeignPath::fdw_restrictinfo, RelOptInfo::lateral_relids, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ForeignPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, Path::rows, Path::startup_cost, and Path::total_cost.

Referenced by add_foreign_final_paths(), add_foreign_grouping_paths(), and add_foreign_ordered_paths().

◆ create_foreignscan_path()

ForeignPath * create_foreignscan_path ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
double  rows,
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 2065 of file pathnode.c.

2074{
2075 ForeignPath *pathnode = makeNode(ForeignPath);
2076
2077 /* Historically some FDWs were confused about when to use this */
2078 Assert(IS_SIMPLE_REL(rel));
2079
2080 pathnode->path.pathtype = T_ForeignScan;
2081 pathnode->path.parent = rel;
2082 pathnode->path.pathtarget = target ? target : rel->reltarget;
2083 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
2084 required_outer);
2085 pathnode->path.parallel_aware = false;
2086 pathnode->path.parallel_safe = rel->consider_parallel;
2087 pathnode->path.parallel_workers = 0;
2088 pathnode->path.rows = rows;
2089 pathnode->path.disabled_nodes = disabled_nodes;
2090 pathnode->path.startup_cost = startup_cost;
2091 pathnode->path.total_cost = total_cost;
2092 pathnode->path.pathkeys = pathkeys;
2093
2094 pathnode->fdw_outerpath = fdw_outerpath;
2095 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2096 pathnode->fdw_private = fdw_private;
2097
2098 return pathnode;
2099}
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:895

References Assert(), RelOptInfo::consider_parallel, Path::disabled_nodes, ForeignPath::fdw_outerpath, ForeignPath::fdw_private, ForeignPath::fdw_restrictinfo, get_baserel_parampathinfo(), IS_SIMPLE_REL, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ForeignPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, root, Path::rows, Path::startup_cost, and Path::total_cost.

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

◆ create_functionscan_path()

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

Definition at line 1876 of file pathnode.c.

1878{
1879 Path *pathnode = makeNode(Path);
1880
1881 pathnode->pathtype = T_FunctionScan;
1882 pathnode->parent = rel;
1883 pathnode->pathtarget = rel->reltarget;
1884 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1885 required_outer);
1886 pathnode->parallel_aware = false;
1887 pathnode->parallel_safe = rel->consider_parallel;
1888 pathnode->parallel_workers = 0;
1889 pathnode->pathkeys = pathkeys;
1890
1891 cost_functionscan(pathnode, root, rel, pathnode->param_info);
1892
1893 return pathnode;
1894}
void cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1512

References RelOptInfo::consider_parallel, cost_functionscan(), get_baserel_parampathinfo(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::pathkeys, Path::pathtype, 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 1750 of file pathnode.c.

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

References Assert(), cost_gather_merge(), elog, ERROR, get_baserel_parampathinfo(), makeNode, GatherMergePath::num_workers, Path::parallel_aware, GatherMergePath::path, Path::pathkeys, pathkeys_contained_in(), Path::pathtype, RelOptInfo::reltarget, root, subpath(), and GatherMergePath::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 1802 of file pathnode.c.

1804{
1805 GatherPath *pathnode = makeNode(GatherPath);
1806
1807 Assert(subpath->parallel_safe);
1808
1809 pathnode->path.pathtype = T_Gather;
1810 pathnode->path.parent = rel;
1811 pathnode->path.pathtarget = target;
1812 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1813 required_outer);
1814 pathnode->path.parallel_aware = false;
1815 pathnode->path.parallel_safe = false;
1816 pathnode->path.parallel_workers = 0;
1817 pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1818
1819 pathnode->subpath = subpath;
1820 pathnode->num_workers = subpath->parallel_workers;
1821 pathnode->single_copy = false;
1822
1823 if (pathnode->num_workers == 0)
1824 {
1825 pathnode->path.pathkeys = subpath->pathkeys;
1826 pathnode->num_workers = 1;
1827 pathnode->single_copy = true;
1828 }
1829
1830 cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1831
1832 return pathnode;
1833}
void cost_gather(GatherPath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, double *rows)
Definition: costsize.c:420
bool single_copy
Definition: pathnodes.h:2264
int num_workers
Definition: pathnodes.h:2265

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

Referenced by generate_gather_paths(), and generate_union_paths().

◆ create_group_path()

GroupPath * create_group_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List groupClause,
List qual,
double  numGroups 
)

Definition at line 2885 of file pathnode.c.

2891{
2892 GroupPath *pathnode = makeNode(GroupPath);
2893 PathTarget *target = rel->reltarget;
2894
2895 pathnode->path.pathtype = T_Group;
2896 pathnode->path.parent = rel;
2897 pathnode->path.pathtarget = target;
2898 /* For now, assume we are above any joins, so no parameterization */
2899 pathnode->path.param_info = NULL;
2900 pathnode->path.parallel_aware = false;
2901 pathnode->path.parallel_safe = rel->consider_parallel &&
2902 subpath->parallel_safe;
2903 pathnode->path.parallel_workers = subpath->parallel_workers;
2904 /* Group doesn't change sort ordering */
2905 pathnode->path.pathkeys = subpath->pathkeys;
2906
2907 pathnode->subpath = subpath;
2908
2909 pathnode->groupClause = groupClause;
2910 pathnode->qual = qual;
2911
2912 cost_group(&pathnode->path, root,
2913 list_length(groupClause),
2914 numGroups,
2915 qual,
2916 subpath->disabled_nodes,
2917 subpath->startup_cost, subpath->total_cost,
2918 subpath->rows);
2919
2920 /* add tlist eval cost for each output row */
2921 pathnode->path.startup_cost += target->cost.startup;
2922 pathnode->path.total_cost += target->cost.startup +
2923 target->cost.per_tuple * pathnode->path.rows;
2924
2925 return pathnode;
2926}
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:3201
List * qual
Definition: pathnodes.h:2457
List * groupClause
Definition: pathnodes.h:2456
Path * subpath
Definition: pathnodes.h:2455
Path path
Definition: pathnodes.h:2454

References RelOptInfo::consider_parallel, PathTarget::cost, cost_group(), GroupPath::groupClause, list_length(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, GroupPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, GroupPath::qual, RelOptInfo::reltarget, root, Path::rows, QualCost::startup, Path::startup_cost, subpath(), GroupPath::subpath, and Path::total_cost.

Referenced by add_paths_to_grouping_rel(), and create_partial_grouping_paths().

◆ create_group_result_path()

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

Definition at line 1609 of file pathnode.c.

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

References RelOptInfo::consider_parallel, PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, GroupResultPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, GroupResultPath::quals, root, Path::rows, QualCost::startup, Path::startup_cost, and Path::total_cost.

Referenced by create_degenerate_grouping_paths(), and query_planner().

◆ create_groupingsets_path()

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

Definition at line 3076 of file pathnode.c.

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

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, GroupingSetsPath::aggstrategy, Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), cost_sort(), Path::disabled_nodes, RollupData::gsets, RollupData::is_hashed, lfirst, linitial, list_length(), makeNode, NIL, RollupData::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, GroupingSetsPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, GroupingSetsPath::qual, RelOptInfo::reltarget, GroupingSetsPath::rollups, root, Path::rows, QualCost::startup, Path::startup_cost, subpath(), GroupingSetsPath::subpath, Path::total_cost, AggClauseCosts::transitionSpace, GroupingSetsPath::transitionSpace, and work_mem.

Referenced by consider_groupingsets_paths().

◆ create_hashjoin_path()

HashPath * create_hashjoin_path ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
JoinCostWorkspace workspace,
JoinPathExtraData extra,
Path outer_path,
Path inner_path,
bool  parallel_hash,
List restrict_clauses,
Relids  required_outer,
List hashclauses 
)

Definition at line 2458 of file pathnode.c.

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

References RelOptInfo::consider_parallel, final_cost_hashjoin(), get_joinrel_parampathinfo(), JoinPath::inner_unique, JoinPathExtraData::inner_unique, JoinPath::innerjoinpath, JoinPath::joinrestrictinfo, JoinPath::jointype, HashPath::jpath, makeNode, NIL, JoinPath::outerjoinpath, Path::parallel_safe, Path::parallel_workers, HashPath::path_hashclauses, RelOptInfo::reltarget, 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 2792 of file pathnode.c.

2798{
2800 SortPath *pathnode = &sort->spath;
2801
2802 pathnode->path.pathtype = T_IncrementalSort;
2803 pathnode->path.parent = rel;
2804 /* Sort doesn't project, so use source path's pathtarget */
2805 pathnode->path.pathtarget = subpath->pathtarget;
2806 pathnode->path.param_info = subpath->param_info;
2807 pathnode->path.parallel_aware = false;
2808 pathnode->path.parallel_safe = rel->consider_parallel &&
2809 subpath->parallel_safe;
2810 pathnode->path.parallel_workers = subpath->parallel_workers;
2811 pathnode->path.pathkeys = pathkeys;
2812
2813 pathnode->subpath = subpath;
2814
2815 cost_incremental_sort(&pathnode->path,
2816 root, pathkeys, presorted_keys,
2817 subpath->disabled_nodes,
2818 subpath->startup_cost,
2819 subpath->total_cost,
2820 subpath->rows,
2821 subpath->pathtarget->width,
2822 0.0, /* XXX comparison_cost shouldn't be 0? */
2823 work_mem, limit_tuples);
2824
2825 sort->nPresortedCols = presorted_keys;
2826
2827 return sort;
2828}
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:1974
Path path
Definition: pathnodes.h:2428
Path * subpath
Definition: pathnodes.h:2429

References RelOptInfo::consider_parallel, cost_incremental_sort(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, SortPath::path, Path::pathkeys, Path::pathtype, root, sort(), subpath(), SortPath::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 1049 of file pathnode.c.

1060{
1061 IndexPath *pathnode = makeNode(IndexPath);
1062 RelOptInfo *rel = index->rel;
1063
1064 pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
1065 pathnode->path.parent = rel;
1066 pathnode->path.pathtarget = rel->reltarget;
1067 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1068 required_outer);
1069 pathnode->path.parallel_aware = false;
1070 pathnode->path.parallel_safe = rel->consider_parallel;
1071 pathnode->path.parallel_workers = 0;
1072 pathnode->path.pathkeys = pathkeys;
1073
1074 pathnode->indexinfo = index;
1075 pathnode->indexclauses = indexclauses;
1076 pathnode->indexorderbys = indexorderbys;
1077 pathnode->indexorderbycols = indexorderbycols;
1078 pathnode->indexscandir = indexscandir;
1079
1080 cost_index(pathnode, root, loop_count, partial_path);
1081
1082 return pathnode;
1083}
void cost_index(IndexPath *path, PlannerInfo *root, double loop_count, bool partial_path)
Definition: costsize.c:534
List * indexclauses
Definition: pathnodes.h:1958
ScanDirection indexscandir
Definition: pathnodes.h:1961
Path path
Definition: pathnodes.h:1956
List * indexorderbycols
Definition: pathnodes.h:1960
List * indexorderbys
Definition: pathnodes.h:1959
IndexOptInfo * indexinfo
Definition: pathnodes.h:1957
Definition: type.h:96

References RelOptInfo::consider_parallel, cost_index(), get_baserel_parampathinfo(), IndexPath::indexclauses, IndexPath::indexinfo, IndexPath::indexorderbycols, IndexPath::indexorderbys, IndexPath::indexscandir, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, IndexPath::path, Path::pathkeys, Path::pathtype, 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 3729 of file pathnode.c.

3734{
3735 LimitPath *pathnode = makeNode(LimitPath);
3736
3737 pathnode->path.pathtype = T_Limit;
3738 pathnode->path.parent = rel;
3739 /* Limit doesn't project, so use source path's pathtarget */
3740 pathnode->path.pathtarget = subpath->pathtarget;
3741 /* For now, assume we are above any joins, so no parameterization */
3742 pathnode->path.param_info = NULL;
3743 pathnode->path.parallel_aware = false;
3744 pathnode->path.parallel_safe = rel->consider_parallel &&
3745 subpath->parallel_safe;
3746 pathnode->path.parallel_workers = subpath->parallel_workers;
3747 pathnode->path.rows = subpath->rows;
3748 pathnode->path.disabled_nodes = subpath->disabled_nodes;
3749 pathnode->path.startup_cost = subpath->startup_cost;
3750 pathnode->path.total_cost = subpath->total_cost;
3751 pathnode->path.pathkeys = subpath->pathkeys;
3752 pathnode->subpath = subpath;
3753 pathnode->limitOffset = limitOffset;
3754 pathnode->limitCount = limitCount;
3755 pathnode->limitOption = limitOption;
3756
3757 /*
3758 * Adjust the output rows count and costs according to the offset/limit.
3759 */
3761 &pathnode->path.startup_cost,
3762 &pathnode->path.total_cost,
3763 offset_est, count_est);
3764
3765 return pathnode;
3766}
void adjust_limit_rows_costs(double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
Definition: pathnode.c:3785
Path path
Definition: pathnodes.h:2627
Path * subpath
Definition: pathnodes.h:2628
LimitOption limitOption
Definition: pathnodes.h:2631
Node * limitOffset
Definition: pathnodes.h:2629
Node * limitCount
Definition: pathnodes.h:2630

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

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

◆ create_lockrows_path()

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

Definition at line 3567 of file pathnode.c.

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

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

Referenced by grouping_planner().

◆ create_material_path()

MaterialPath * create_material_path ( RelOptInfo rel,
Path subpath 
)

Definition at line 1657 of file pathnode.c.

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

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

Referenced by consider_parallel_nestloop(), match_unsorted_outer(), reparameterize_path(), and set_tablesample_rel_pathlist().

◆ create_memoize_path()

MemoizePath * create_memoize_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List param_exprs,
List hash_operators,
bool  singlerow,
bool  binary_mode,
Cardinality  est_calls 
)

Definition at line 1690 of file pathnode.c.

1693{
1694 MemoizePath *pathnode = makeNode(MemoizePath);
1695
1696 Assert(subpath->parent == rel);
1697
1698 pathnode->path.pathtype = T_Memoize;
1699 pathnode->path.parent = rel;
1700 pathnode->path.pathtarget = rel->reltarget;
1701 pathnode->path.param_info = subpath->param_info;
1702 pathnode->path.parallel_aware = false;
1703 pathnode->path.parallel_safe = rel->consider_parallel &&
1704 subpath->parallel_safe;
1705 pathnode->path.parallel_workers = subpath->parallel_workers;
1706 pathnode->path.pathkeys = subpath->pathkeys;
1707
1708 pathnode->subpath = subpath;
1709 pathnode->hash_operators = hash_operators;
1710 pathnode->param_exprs = param_exprs;
1711 pathnode->singlerow = singlerow;
1712 pathnode->binary_mode = binary_mode;
1713
1714 /*
1715 * For now we set est_entries to 0. cost_memoize_rescan() does all the
1716 * hard work to determine how many cache entries there are likely to be,
1717 * so it seems best to leave it up to that function to fill this field in.
1718 * If left at 0, the executor will make a guess at a good value.
1719 */
1720 pathnode->est_entries = 0;
1721
1722 pathnode->est_calls = clamp_row_est(est_calls);
1723
1724 /* These will also be set later in cost_memoize_rescan() */
1725 pathnode->est_unique_keys = 0.0;
1726 pathnode->est_hit_ratio = 0.0;
1727
1728 /* we should not generate this path type when enable_memoize=false */
1730 pathnode->path.disabled_nodes = subpath->disabled_nodes;
1731
1732 /*
1733 * Add a small additional charge for caching the first entry. All the
1734 * harder calculations for rescans are performed in cost_memoize_rescan().
1735 */
1736 pathnode->path.startup_cost = subpath->startup_cost + cpu_tuple_cost;
1737 pathnode->path.total_cost = subpath->total_cost + cpu_tuple_cost;
1738 pathnode->path.rows = subpath->rows;
1739
1740 return pathnode;
1741}
bool enable_memoize
Definition: costsize.c:155
Cardinality est_calls
Definition: pathnodes.h:2250
bool singlerow
Definition: pathnodes.h:2243
List * hash_operators
Definition: pathnodes.h:2241
uint32 est_entries
Definition: pathnodes.h:2247
bool binary_mode
Definition: pathnodes.h:2245
double est_hit_ratio
Definition: pathnodes.h:2252
Cardinality est_unique_keys
Definition: pathnodes.h:2251
Path * subpath
Definition: pathnodes.h:2240
List * param_exprs
Definition: pathnodes.h:2242

References Assert(), MemoizePath::binary_mode, clamp_row_est(), RelOptInfo::consider_parallel, cpu_tuple_cost, Path::disabled_nodes, enable_memoize, MemoizePath::est_calls, MemoizePath::est_entries, MemoizePath::est_hit_ratio, MemoizePath::est_unique_keys, MemoizePath::hash_operators, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, MemoizePath::param_exprs, MemoizePath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, Path::rows, MemoizePath::singlerow, Path::startup_cost, subpath(), MemoizePath::subpath, and Path::total_cost.

Referenced by get_memoize_path(), and reparameterize_path().

◆ create_merge_append_path()

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

Definition at line 1471 of file pathnode.c.

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

References Assert(), bms_equal(), bms_is_empty, RelOptInfo::consider_parallel, cost_incremental_sort(), cost_merge_append(), cost_sort(), Path::disabled_nodes, enable_incremental_sort, RelOptInfo::lateral_relids, lfirst, MergeAppendPath::limit_tuples, linitial, list_length(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, MergeAppendPath::path, PATH_REQ_OUTER, Path::pathkeys, pathkeys_count_contained_in(), Path::pathtype, RelOptInfo::relids, RelOptInfo::reltarget, root, Path::rows, Path::startup_cost, subpath(), MergeAppendPath::subpaths, Path::total_cost, 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 2390 of file pathnode.c.

2404{
2405 MergePath *pathnode = makeNode(MergePath);
2406
2407 pathnode->jpath.path.pathtype = T_MergeJoin;
2408 pathnode->jpath.path.parent = joinrel;
2409 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2410 pathnode->jpath.path.param_info =
2412 joinrel,
2413 outer_path,
2414 inner_path,
2415 extra->sjinfo,
2416 required_outer,
2417 &restrict_clauses);
2418 pathnode->jpath.path.parallel_aware = false;
2419 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2420 outer_path->parallel_safe && inner_path->parallel_safe;
2421 /* This is a foolish way to estimate parallel_workers, but for now... */
2422 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2423 pathnode->jpath.path.pathkeys = pathkeys;
2424 pathnode->jpath.jointype = jointype;
2425 pathnode->jpath.inner_unique = extra->inner_unique;
2426 pathnode->jpath.outerjoinpath = outer_path;
2427 pathnode->jpath.innerjoinpath = inner_path;
2428 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2429 pathnode->path_mergeclauses = mergeclauses;
2430 pathnode->outersortkeys = outersortkeys;
2431 pathnode->innersortkeys = innersortkeys;
2432 pathnode->outer_presorted_keys = outer_presorted_keys;
2433 /* pathnode->skip_mark_restore will be set by final_cost_mergejoin */
2434 /* pathnode->materialize_inner will be set by final_cost_mergejoin */
2435
2436 final_cost_mergejoin(root, pathnode, workspace, extra);
2437
2438 return pathnode;
2439}
void final_cost_mergejoin(PlannerInfo *root, MergePath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition: costsize.c:3843
List * outersortkeys
Definition: pathnodes.h:2361
List * innersortkeys
Definition: pathnodes.h:2362
JoinPath jpath
Definition: pathnodes.h:2359
int outer_presorted_keys
Definition: pathnodes.h:2363
List * path_mergeclauses
Definition: pathnodes.h:2360

References RelOptInfo::consider_parallel, final_cost_mergejoin(), get_joinrel_parampathinfo(), JoinPath::inner_unique, JoinPathExtraData::inner_unique, JoinPath::innerjoinpath, MergePath::innersortkeys, JoinPath::joinrestrictinfo, JoinPath::jointype, MergePath::jpath, makeNode, MergePath::outer_presorted_keys, JoinPath::outerjoinpath, MergePath::outersortkeys, Path::parallel_safe, Path::parallel_workers, MergePath::path_mergeclauses, 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 3239 of file pathnode.c.

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

References PathTarget::cost, cost_qual_eval(), cpu_tuple_cost, Path::disabled_nodes, PathTarget::exprs, is_parallel_safe(), lfirst, makeNode, MinMaxAggPath::mmaggregates, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, MinMaxAggPath::path, MinMaxAggInfo::path, MinMaxAggInfo::pathcost, Path::pathkeys, Path::pathtype, QualCost::per_tuple, MinMaxAggPath::quals, root, Path::rows, QualCost::startup, Path::startup_cost, and Path::total_cost.

Referenced by preprocess_minmax_aggregates().

◆ create_modifytable_path()

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

Definition at line 3629 of file pathnode.c.

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

References Assert(), ModifyTablePath::canSetTag, CMD_MERGE, CMD_UPDATE, Path::disabled_nodes, ModifyTablePath::epqParam, list_length(), makeNode, ModifyTablePath::mergeActionLists, ModifyTablePath::mergeJoinConditions, NIL, ModifyTablePath::nominalRelation, ModifyTablePath::onconflict, ModifyTablePath::operation, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ModifyTablePath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, ModifyTablePath::resultRelations, ModifyTablePath::returningLists, ModifyTablePath::rootRelation, ModifyTablePath::rowMarks, Path::rows, Path::startup_cost, subpath(), ModifyTablePath::subpath, Path::total_cost, ModifyTablePath::updateColnosLists, and ModifyTablePath::withCheckOptionLists.

Referenced by grouping_planner().

◆ create_namedtuplestorescan_path()

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

Definition at line 1980 of file pathnode.c.

1982{
1983 Path *pathnode = makeNode(Path);
1984
1985 pathnode->pathtype = T_NamedTuplestoreScan;
1986 pathnode->parent = rel;
1987 pathnode->pathtarget = rel->reltarget;
1988 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1989 required_outer);
1990 pathnode->parallel_aware = false;
1991 pathnode->parallel_safe = rel->consider_parallel;
1992 pathnode->parallel_workers = 0;
1993 pathnode->pathkeys = NIL; /* result is always unordered */
1994
1995 cost_namedtuplestorescan(pathnode, root, rel, pathnode->param_info);
1996
1997 return pathnode;
1998}
void cost_namedtuplestorescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1724

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

2303{
2304 NestPath *pathnode = makeNode(NestPath);
2305 Relids inner_req_outer = PATH_REQ_OUTER(inner_path);
2306 Relids outerrelids;
2307
2308 /*
2309 * Paths are parameterized by top-level parents, so run parameterization
2310 * tests on the parent relids.
2311 */
2312 if (outer_path->parent->top_parent_relids)
2313 outerrelids = outer_path->parent->top_parent_relids;
2314 else
2315 outerrelids = outer_path->parent->relids;
2316
2317 /*
2318 * If the inner path is parameterized by the outer, we must drop any
2319 * restrict_clauses that are due to be moved into the inner path. We have
2320 * to do this now, rather than postpone the work till createplan time,
2321 * because the restrict_clauses list can affect the size and cost
2322 * estimates for this path. We detect such clauses by checking for serial
2323 * number match to clauses already enforced in the inner path.
2324 */
2325 if (bms_overlap(inner_req_outer, outerrelids))
2326 {
2327 Bitmapset *enforced_serials = get_param_path_clause_serials(inner_path);
2328 List *jclauses = NIL;
2329 ListCell *lc;
2330
2331 foreach(lc, restrict_clauses)
2332 {
2333 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2334
2335 if (!bms_is_member(rinfo->rinfo_serial, enforced_serials))
2336 jclauses = lappend(jclauses, rinfo);
2337 }
2338 restrict_clauses = jclauses;
2339 }
2340
2341 pathnode->jpath.path.pathtype = T_NestLoop;
2342 pathnode->jpath.path.parent = joinrel;
2343 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2344 pathnode->jpath.path.param_info =
2346 joinrel,
2347 outer_path,
2348 inner_path,
2349 extra->sjinfo,
2350 required_outer,
2351 &restrict_clauses);
2352 pathnode->jpath.path.parallel_aware = false;
2353 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2354 outer_path->parallel_safe && inner_path->parallel_safe;
2355 /* This is a foolish way to estimate parallel_workers, but for now... */
2356 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2357 pathnode->jpath.path.pathkeys = pathkeys;
2358 pathnode->jpath.jointype = jointype;
2359 pathnode->jpath.inner_unique = extra->inner_unique;
2360 pathnode->jpath.outerjoinpath = outer_path;
2361 pathnode->jpath.innerjoinpath = inner_path;
2362 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2363
2364 final_cost_nestloop(root, pathnode, workspace, extra);
2365
2366 return pathnode;
2367}
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:3355
List * lappend(List *list, void *datum)
Definition: list.c:339
Bitmapset * get_param_path_clause_serials(Path *path)
Definition: relnode.c:2032
JoinPath jpath
Definition: pathnodes.h:2313
int rinfo_serial
Definition: pathnodes.h:2863

References bms_is_member(), bms_overlap(), RelOptInfo::consider_parallel, final_cost_nestloop(), get_joinrel_parampathinfo(), get_param_path_clause_serials(), JoinPath::inner_unique, JoinPathExtraData::inner_unique, JoinPath::innerjoinpath, JoinPath::joinrestrictinfo, JoinPath::jointype, NestPath::jpath, lappend(), lfirst, makeNode, NIL, JoinPath::outerjoinpath, Path::parallel_safe, Path::parallel_workers, PATH_REQ_OUTER, RelOptInfo::reltarget, RestrictInfo::rinfo_serial, 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 2524 of file pathnode.c.

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

References Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cpu_tuple_cost, Path::disabled_nodes, ProjectionPath::dummypp, equal(), PathTarget::exprs, is_parallel_safe(), is_projection_capable_path(), IsA, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ProjectionPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, root, Path::rows, QualCost::startup, Path::startup_cost, subpath(), ProjectionPath::subpath, and Path::total_cost.

Referenced by add_paths_with_pathkeys_for_rel(), adjust_paths_for_srfs(), apply_projection_to_path(), apply_scanjoin_target_to_paths(), 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 3522 of file pathnode.c.

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

References RelOptInfo::consider_parallel, cost_recursive_union(), RecursiveUnionPath::distinctList, RecursiveUnionPath::leftpath, makeNode, NIL, RecursiveUnionPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, RecursiveUnionPath::path, Path::pathkeys, Path::pathtype, RecursiveUnionPath::rightpath, and RecursiveUnionPath::wtParam.

Referenced by generate_recursion_path().

◆ create_resultscan_path()

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

Definition at line 2006 of file pathnode.c.

2008{
2009 Path *pathnode = makeNode(Path);
2010
2011 pathnode->pathtype = T_Result;
2012 pathnode->parent = rel;
2013 pathnode->pathtarget = rel->reltarget;
2014 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2015 required_outer);
2016 pathnode->parallel_aware = false;
2017 pathnode->parallel_safe = rel->consider_parallel;
2018 pathnode->parallel_workers = 0;
2019 pathnode->pathkeys = NIL; /* result is always unordered */
2020
2021 cost_resultscan(pathnode, root, rel, pathnode->param_info);
2022
2023 return pathnode;
2024}
void cost_resultscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1762

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

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

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

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

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

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

References RelOptInfo::consider_parallel, PathTarget::cost, cpu_tuple_cost, Path::disabled_nodes, expression_returns_set_rows(), PathTarget::exprs, is_parallel_safe(), lfirst, makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, ProjectSetPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, root, Path::rows, QualCost::startup, Path::startup_cost, subpath(), ProjectSetPath::subpath, and Path::total_cost.

Referenced by adjust_paths_for_srfs().

◆ create_setop_path()

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

Definition at line 3403 of file pathnode.c.

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

References SetOpPath::cmd, RelOptInfo::consider_parallel, cpu_operator_cost, Path::disabled_nodes, enable_hashagg, EstimateSetOpHashTableSpace(), get_hash_memory_limit(), SetOpPath::groupList, if(), SetOpPath::leftpath, list_length(), makeNode, NIL, SetOpPath::numGroups, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, SetOpPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, SetOpPath::rightpath, Path::rows, SETOP_SORTED, Path::startup_cost, SetOpPath::strategy, 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 2841 of file pathnode.c.

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

References RelOptInfo::consider_parallel, cost_sort(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, SortPath::path, Path::pathkeys, Path::pathtype, root, subpath(), SortPath::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 1846 of file pathnode.c.

1849{
1851
1852 pathnode->path.pathtype = T_SubqueryScan;
1853 pathnode->path.parent = rel;
1854 pathnode->path.pathtarget = rel->reltarget;
1855 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1856 required_outer);
1857 pathnode->path.parallel_aware = false;
1858 pathnode->path.parallel_safe = rel->consider_parallel &&
1859 subpath->parallel_safe;
1860 pathnode->path.parallel_workers = subpath->parallel_workers;
1861 pathnode->path.pathkeys = pathkeys;
1862 pathnode->subpath = subpath;
1863
1864 cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
1865 trivial_pathtarget);
1866
1867 return pathnode;
1868}
void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, bool trivial_pathtarget)
Definition: costsize.c:1431

References RelOptInfo::consider_parallel, cost_subqueryscan(), get_baserel_parampathinfo(), makeNode, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, SubqueryScanPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, root, subpath(), and SubqueryScanPath::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 1902 of file pathnode.c.

1904{
1905 Path *pathnode = makeNode(Path);
1906
1907 pathnode->pathtype = T_TableFuncScan;
1908 pathnode->parent = rel;
1909 pathnode->pathtarget = rel->reltarget;
1910 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1911 required_outer);
1912 pathnode->parallel_aware = false;
1913 pathnode->parallel_safe = rel->consider_parallel;
1914 pathnode->parallel_workers = 0;
1915 pathnode->pathkeys = NIL; /* result is always unordered */
1916
1917 cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
1918
1919 return pathnode;
1920}
void cost_tablefuncscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1574

References RelOptInfo::consider_parallel, cost_tablefuncscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, Path::pathkeys, Path::pathtype, 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 
)

Definition at line 1264 of file pathnode.c.

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

References RelOptInfo::consider_parallel, cost_tidrangescan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, TidRangePath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, root, and TidRangePath::tidrangequals.

Referenced by create_tidscan_paths().

◆ create_tidscan_path()

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

Definition at line 1235 of file pathnode.c.

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

References RelOptInfo::consider_parallel, cost_tidscan(), get_baserel_parampathinfo(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, TidPath::path, Path::pathkeys, Path::pathtype, RelOptInfo::reltarget, root, and TidPath::tidquals.

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

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

References RelOptInfo::consider_parallel, cpu_operator_cost, Path::disabled_nodes, makeNode, UniquePath::numkeys, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, UniquePath::path, Path::pathkeys, Path::pathtype, Path::rows, Path::startup_cost, subpath(), UniquePath::subpath, and Path::total_cost.

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

1930{
1931 Path *pathnode = makeNode(Path);
1932
1933 pathnode->pathtype = T_ValuesScan;
1934 pathnode->parent = rel;
1935 pathnode->pathtarget = rel->reltarget;
1936 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1937 required_outer);
1938 pathnode->parallel_aware = false;
1939 pathnode->parallel_safe = rel->consider_parallel;
1940 pathnode->parallel_workers = 0;
1941 pathnode->pathkeys = NIL; /* result is always unordered */
1942
1943 cost_valuesscan(pathnode, root, rel, pathnode->param_info);
1944
1945 return pathnode;
1946}
void cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition: costsize.c:1631

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

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

References Assert(), RelOptInfo::consider_parallel, PathTarget::cost, cost_windowagg(), makeNode, NIL, Path::parallel_aware, Path::parallel_safe, Path::parallel_workers, WindowAggPath::path, Path::pathkeys, Path::pathtype, QualCost::per_tuple, WindowAggPath::qual, root, Path::rows, WindowAggPath::runCondition, QualCost::startup, Path::startup_cost, subpath(), WindowAggPath::subpath, WindowAggPath::topwindow, Path::total_cost, and WindowAggPath::winclause.

Referenced by create_one_window_path().

◆ create_worktablescan_path()

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

Definition at line 2032 of file pathnode.c.

2034{
2035 Path *pathnode = makeNode(Path);
2036
2037 pathnode->pathtype = T_WorkTableScan;
2038 pathnode->parent = rel;
2039 pathnode->pathtarget = rel->reltarget;
2040 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2041 required_outer);
2042 pathnode->parallel_aware = false;
2043 pathnode->parallel_safe = rel->consider_parallel;
2044 pathnode->parallel_workers = 0;
2045 pathnode->pathkeys = NIL; /* result is always unordered */
2046
2047 /* Cost is the same as for a regular CTE scan */
2048 cost_ctescan(pathnode, root, rel, pathnode->param_info);
2049
2050 return pathnode;
2051}

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

4316{
4317#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE(path) \
4318do { \
4319 if (!path_is_reparameterizable_by_child(path, child_rel)) \
4320 return false; \
4321} while(0)
4322
4323#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE(pathlist) \
4324do { \
4325 if (!pathlist_is_reparameterizable_by_child(pathlist, child_rel)) \
4326 return false; \
4327} while(0)
4328
4329 /*
4330 * If the path is not parameterized by the parent of the given relation,
4331 * it doesn't need reparameterization.
4332 */
4333 if (!path->param_info ||
4334 !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4335 return true;
4336
4337 /*
4338 * Check that the path type is one that reparameterize_path_by_child() can
4339 * handle, and recursively check subpaths.
4340 */
4341 switch (nodeTag(path))
4342 {
4343 case T_Path:
4344 case T_IndexPath:
4345 break;
4346
4347 case T_BitmapHeapPath:
4348 {
4349 BitmapHeapPath *bhpath = (BitmapHeapPath *) path;
4350
4352 }
4353 break;
4354
4355 case T_BitmapAndPath:
4356 {
4357 BitmapAndPath *bapath = (BitmapAndPath *) path;
4358
4360 }
4361 break;
4362
4363 case T_BitmapOrPath:
4364 {
4365 BitmapOrPath *bopath = (BitmapOrPath *) path;
4366
4368 }
4369 break;
4370
4371 case T_ForeignPath:
4372 {
4373 ForeignPath *fpath = (ForeignPath *) path;
4374
4375 if (fpath->fdw_outerpath)
4377 }
4378 break;
4379
4380 case T_CustomPath:
4381 {
4382 CustomPath *cpath = (CustomPath *) path;
4383
4385 }
4386 break;
4387
4388 case T_NestPath:
4389 case T_MergePath:
4390 case T_HashPath:
4391 {
4392 JoinPath *jpath = (JoinPath *) path;
4393
4396 }
4397 break;
4398
4399 case T_AppendPath:
4400 {
4401 AppendPath *apath = (AppendPath *) path;
4402
4404 }
4405 break;
4406
4407 case T_MaterialPath:
4408 {
4409 MaterialPath *mpath = (MaterialPath *) path;
4410
4412 }
4413 break;
4414
4415 case T_MemoizePath:
4416 {
4417 MemoizePath *mpath = (MemoizePath *) path;
4418
4420 }
4421 break;
4422
4423 case T_GatherPath:
4424 {
4425 GatherPath *gpath = (GatherPath *) path;
4426
4428 }
4429 break;
4430
4431 default:
4432 /* We don't know how to reparameterize this path. */
4433 return false;
4434 }
4435
4436 return true;
4437}
#define nodeTag(nodeptr)
Definition: nodes.h:139
#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE(pathlist)
#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE(path)
List * custom_paths
Definition: pathnodes.h:2155
Relids top_parent_relids
Definition: pathnodes.h:1078

References BitmapHeapPath::bitmapqual, BitmapAndPath::bitmapquals, BitmapOrPath::bitmapquals, bms_overlap(), CustomPath::custom_paths, ForeignPath::fdw_outerpath, JoinPath::innerjoinpath, nodeTag, JoinPath::outerjoinpath, PATH_REQ_OUTER, REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE, REJECT_IF_PATH_NOT_REPARAMETERIZABLE, MaterialPath::subpath, MemoizePath::subpath, GatherPath::subpath, AppendPath::subpaths, and RelOptInfo::top_parent_relids.

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

4476{
4477 ListCell *lc;
4478
4479 foreach(lc, pathlist)
4480 {
4481 Path *path = (Path *) lfirst(lc);
4482
4483 if (!path_is_reparameterizable_by_child(path, child_rel))
4484 return false;
4485 }
4486
4487 return true;
4488}

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

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

References MemoizePath::binary_mode, BitmapHeapPath::bitmapqual, 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(), MemoizePath::est_calls, get_baserel_parampathinfo(), MemoizePath::hash_operators, i, IsA, lappend(), lfirst, makeNode, NIL, Path::parallel_aware, Path::parallel_workers, MemoizePath::param_exprs, IndexPath::path, SubqueryScanPath::path, AppendPath::path, PATH_REQ_OUTER, Path::pathkeys, Path::pathtype, reparameterize_path(), root, MemoizePath::singlerow, subpath(), SubqueryScanPath::subpath, MaterialPath::subpath, MemoizePath::subpath, AppendPath::subpaths, 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 4019 of file pathnode.c.

4021{
4022 Path *new_path;
4023 ParamPathInfo *new_ppi;
4024 ParamPathInfo *old_ppi;
4025 Relids required_outer;
4026
4027#define ADJUST_CHILD_ATTRS(node) \
4028 ((node) = (void *) adjust_appendrel_attrs_multilevel(root, \
4029 (Node *) (node), \
4030 child_rel, \
4031 child_rel->top_parent))
4032
4033#define REPARAMETERIZE_CHILD_PATH(path) \
4034do { \
4035 (path) = reparameterize_path_by_child(root, (path), child_rel); \
4036 if ((path) == NULL) \
4037 return NULL; \
4038} while(0)
4039
4040#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
4041do { \
4042 if ((pathlist) != NIL) \
4043 { \
4044 (pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
4045 child_rel); \
4046 if ((pathlist) == NIL) \
4047 return NULL; \
4048 } \
4049} while(0)
4050
4051 /*
4052 * If the path is not parameterized by the parent of the given relation,
4053 * it doesn't need reparameterization.
4054 */
4055 if (!path->param_info ||
4056 !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4057 return path;
4058
4059 /*
4060 * If possible, reparameterize the given path.
4061 *
4062 * This function is currently only applied to the inner side of a nestloop
4063 * join that is being partitioned by the partitionwise-join code. Hence,
4064 * we need only support path types that plausibly arise in that context.
4065 * (In particular, supporting sorted path types would be a waste of code
4066 * and cycles: even if we translated them here, they'd just lose in
4067 * subsequent cost comparisons.) If we do see an unsupported path type,
4068 * that just means we won't be able to generate a partitionwise-join plan
4069 * using that path type.
4070 */
4071 switch (nodeTag(path))
4072 {
4073 case T_Path:
4074 new_path = path;
4075 ADJUST_CHILD_ATTRS(new_path->parent->baserestrictinfo);
4076 if (path->pathtype == T_SampleScan)
4077 {
4078 Index scan_relid = path->parent->relid;
4079 RangeTblEntry *rte;
4080
4081 /* it should be a base rel with a tablesample clause... */
4082 Assert(scan_relid > 0);
4083 rte = planner_rt_fetch(scan_relid, root);
4084 Assert(rte->rtekind == RTE_RELATION);
4085 Assert(rte->tablesample != NULL);
4086
4088 }
4089 break;
4090
4091 case T_IndexPath:
4092 {
4093 IndexPath *ipath = (IndexPath *) path;
4094
4097 new_path = (Path *) ipath;
4098 }
4099 break;
4100
4101 case T_BitmapHeapPath:
4102 {
4103 BitmapHeapPath *bhpath = (BitmapHeapPath *) path;
4104
4105 ADJUST_CHILD_ATTRS(bhpath->path.parent->baserestrictinfo);
4107 new_path = (Path *) bhpath;
4108 }
4109 break;
4110
4111 case T_BitmapAndPath:
4112 {
4113 BitmapAndPath *bapath = (BitmapAndPath *) path;
4114
4116 new_path = (Path *) bapath;
4117 }
4118 break;
4119
4120 case T_BitmapOrPath:
4121 {
4122 BitmapOrPath *bopath = (BitmapOrPath *) path;
4123
4125 new_path = (Path *) bopath;
4126 }
4127 break;
4128
4129 case T_ForeignPath:
4130 {
4131 ForeignPath *fpath = (ForeignPath *) path;
4133
4134 ADJUST_CHILD_ATTRS(fpath->path.parent->baserestrictinfo);
4135 if (fpath->fdw_outerpath)
4137 if (fpath->fdw_restrictinfo)
4139
4140 /* Hand over to FDW if needed. */
4141 rfpc_func =
4142 path->parent->fdwroutine->ReparameterizeForeignPathByChild;
4143 if (rfpc_func)
4144 fpath->fdw_private = rfpc_func(root, fpath->fdw_private,
4145 child_rel);
4146 new_path = (Path *) fpath;
4147 }
4148 break;
4149
4150 case T_CustomPath:
4151 {
4152 CustomPath *cpath = (CustomPath *) path;
4153
4154 ADJUST_CHILD_ATTRS(cpath->path.parent->baserestrictinfo);
4156 if (cpath->custom_restrictinfo)
4158 if (cpath->methods &&
4160 cpath->custom_private =
4162 cpath->custom_private,
4163 child_rel);
4164 new_path = (Path *) cpath;
4165 }
4166 break;
4167
4168 case T_NestPath:
4169 {
4170 NestPath *npath = (NestPath *) path;
4171 JoinPath *jpath = (JoinPath *) npath;
4172
4176 new_path = (Path *) npath;
4177 }
4178 break;
4179
4180 case T_MergePath:
4181 {
4182 MergePath *mpath = (MergePath *) path;
4183 JoinPath *jpath = (JoinPath *) mpath;
4184
4189 new_path = (Path *) mpath;
4190 }
4191 break;
4192
4193 case T_HashPath:
4194 {
4195 HashPath *hpath = (HashPath *) path;
4196 JoinPath *jpath = (JoinPath *) hpath;
4197
4202 new_path = (Path *) hpath;
4203 }
4204 break;
4205
4206 case T_AppendPath:
4207 {
4208 AppendPath *apath = (AppendPath *) path;
4209
4211 new_path = (Path *) apath;
4212 }
4213 break;
4214
4215 case T_MaterialPath:
4216 {
4217 MaterialPath *mpath = (MaterialPath *) path;
4218
4220 new_path = (Path *) mpath;
4221 }
4222 break;
4223
4224 case T_MemoizePath:
4225 {
4226 MemoizePath *mpath = (MemoizePath *) path;
4227
4230 new_path = (Path *) mpath;
4231 }
4232 break;
4233
4234 case T_GatherPath:
4235 {
4236 GatherPath *gpath = (GatherPath *) path;
4237
4239 new_path = (Path *) gpath;
4240 }
4241 break;
4242
4243 default:
4244 /* We don't know how to reparameterize this path. */
4245 return NULL;
4246 }
4247
4248 /*
4249 * Adjust the parameterization information, which refers to the topmost
4250 * parent. The topmost parent can be multiple levels away from the given
4251 * child, hence use multi-level expression adjustment routines.
4252 */
4253 old_ppi = new_path->param_info;
4254 required_outer =
4256 child_rel,
4257 child_rel->top_parent);
4258
4259 /* If we already have a PPI for this parameterization, just return it */
4260 new_ppi = find_param_path_info(new_path->parent, required_outer);
4261
4262 /*
4263 * If not, build a new one and link it to the list of PPIs. For the same
4264 * reason as explained in mark_dummy_rel(), allocate new PPI in the same
4265 * context the given RelOptInfo is in.
4266 */
4267 if (new_ppi == NULL)
4268 {
4269 MemoryContext oldcontext;
4270 RelOptInfo *rel = path->parent;
4271
4273
4274 new_ppi = makeNode(ParamPathInfo);
4275 new_ppi->ppi_req_outer = bms_copy(required_outer);
4276 new_ppi->ppi_rows = old_ppi->ppi_rows;
4277 new_ppi->ppi_clauses = old_ppi->ppi_clauses;
4279 new_ppi->ppi_serials = bms_copy(old_ppi->ppi_serials);
4280 rel->ppilist = lappend(rel->ppilist, new_ppi);
4281
4282 MemoryContextSwitchTo(oldcontext);
4283 }
4284 bms_free(required_outer);
4285
4286 new_path->param_info = new_ppi;
4287
4288 /*
4289 * Adjust the path target if the parent of the outer relation is
4290 * referenced in the targetlist. This can happen when only the parent of
4291 * outer relation is laterally referenced in this relation.
4292 */
4293 if (bms_overlap(path->parent->lateral_relids,
4294 child_rel->top_parent_relids))
4295 {
4296 new_path->pathtarget = copy_pathtarget(new_path->pathtarget);
4297 ADJUST_CHILD_ATTRS(new_path->pathtarget->exprs);
4298 }
4299
4300 return new_path;
4301}
Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition: appendinfo.c:659
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
unsigned int Index
Definition: c.h:623
List *(* ReparameterizeForeignPathByChild_function)(PlannerInfo *root, List *fdw_private, RelOptInfo *child_rel)
Definition: fdwapi.h:182
MemoryContext GetMemoryChunkContext(void *pointer)
Definition: mcxt.c:753
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
@ RTE_RELATION
Definition: parsenodes.h:1043
#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:610
ParamPathInfo * find_param_path_info(RelOptInfo *rel, Relids required_outer)
Definition: relnode.c:2011
struct List *(* ReparameterizeCustomPathByChild)(PlannerInfo *root, List *custom_private, RelOptInfo *child_rel)
Definition: extensible.h:103
const struct CustomPathMethods * methods
Definition: pathnodes.h:2158
List * custom_private
Definition: pathnodes.h:2157
List * custom_restrictinfo
Definition: pathnodes.h:2156
List * indrestrictinfo
Definition: pathnodes.h:1320
Cardinality ppi_rows
Definition: pathnodes.h:1826
List * ppi_clauses
Definition: pathnodes.h:1827
Bitmapset * ppi_serials
Definition: pathnodes.h:1828
Relids ppi_req_outer
Definition: pathnodes.h:1825
struct TableSampleClause * tablesample
Definition: parsenodes.h:1129
RTEKind rtekind
Definition: parsenodes.h:1078
List * ppilist
Definition: pathnodes.h:955
PathTarget * copy_pathtarget(PathTarget *src)
Definition: tlist.c:657

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

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

4449{
4450 ListCell *lc;
4451 List *result = NIL;
4452
4453 foreach(lc, pathlist)
4454 {
4456 child_rel);
4457
4458 if (path == NULL)
4459 {
4460 list_free(result);
4461 return NIL;
4462 }
4463
4464 result = lappend(result, path);
4465 }
4466
4467 return result;
4468}
void list_free(List *list)
Definition: list.c:1546

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

◆ set_cheapest()

void set_cheapest ( RelOptInfo parent_rel)

Definition at line 270 of file pathnode.c.

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

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

Referenced by apply_scanjoin_target_to_paths(), create_distinct_paths(), create_grouping_paths(), create_ordinary_grouping_paths(), create_partial_distinct_paths(), create_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().