PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pathnode.h File Reference
#include "nodes/bitmapset.h"
#include "nodes/pathnodes.h"
Include dependency graph for pathnode.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  AppendPathInput
 

Typedefs

typedef void(* build_simple_rel_hook_type) (PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 
typedef struct AppendPathInput AppendPathInput
 
typedef void(* joinrel_setup_hook_type) (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
 

Functions

int compare_path_costs (Path *path1, Path *path2, CostSelector criterion)
 
int compare_fractional_path_costs (Path *path1, Path *path2, double fraction)
 
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 startup_cost, Cost total_cost, List *pathkeys)
 
Pathcreate_seqscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
 
Pathcreate_samplescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
IndexPathcreate_index_path (PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
 
BitmapHeapPathcreate_bitmap_heap_path (PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
 
BitmapAndPathcreate_bitmap_and_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
BitmapOrPathcreate_bitmap_or_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
TidPathcreate_tidscan_path (PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
 
TidRangePathcreate_tidrangescan_path (PlannerInfo *root, RelOptInfo *rel, List *tidrangequals, Relids required_outer, int parallel_workers)
 
AppendPathcreate_append_path (PlannerInfo *root, RelOptInfo *rel, AppendPathInput input, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *child_append_relid_sets, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath, bool enabled)
 
MemoizePathcreate_memoize_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, Cardinality est_calls)
 
GatherPathcreate_gather_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
 
GatherMergePathcreate_gather_merge_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *pathkeys, 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_valuesscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_tablefuncscan_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)
 
SortPathcreate_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
 
IncrementalSortPathcreate_incremental_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, 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)
 
void setup_simple_rel_arrays (PlannerInfo *root)
 
void expand_planner_arrays (PlannerInfo *root, int add_size)
 
RelOptInfobuild_simple_rel (PlannerInfo *root, int relid, RelOptInfo *parent)
 
RelOptInfobuild_simple_grouped_rel (PlannerInfo *root, RelOptInfo *rel)
 
RelOptInfobuild_grouped_rel (PlannerInfo *root, RelOptInfo *rel)
 
RelOptInfofind_base_rel (PlannerInfo *root, int relid)
 
RelOptInfofind_base_rel_noerr (PlannerInfo *root, int relid)
 
RelOptInfofind_base_rel_ignore_join (PlannerInfo *root, int relid)
 
RelOptInfofind_join_rel (PlannerInfo *root, Relids relids)
 
RelOptInfobuild_join_rel (PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *pushed_down_joins, List **restrictlist_ptr)
 
Relids min_join_parameterization (PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
 
RelOptInfofetch_upper_rel (PlannerInfo *root, UpperRelationKind kind, Relids relids)
 
Relids find_childrel_parents (PlannerInfo *root, RelOptInfo *rel)
 
ParamPathInfoget_baserel_parampathinfo (PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
 
ParamPathInfoget_joinrel_parampathinfo (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, Relids required_outer, List **restrict_clauses)
 
ParamPathInfoget_appendrel_parampathinfo (RelOptInfo *appendrel, Relids required_outer)
 
ParamPathInfofind_param_path_info (RelOptInfo *rel, Relids required_outer)
 
Bitmapsetget_param_path_clause_serials (Path *path)
 
RelOptInfobuild_child_join_rel (PlannerInfo *root, RelOptInfo *outer_rel, RelOptInfo *inner_rel, RelOptInfo *parent_joinrel, List *restrictlist, SpecialJoinInfo *sjinfo, int nappinfos, AppendRelInfo **appinfos)
 
RelAggInfocreate_rel_agg_info (PlannerInfo *root, RelOptInfo *rel, bool calculate_grouped_rows)
 

Variables

PGDLLIMPORT build_simple_rel_hook_type build_simple_rel_hook
 
PGDLLIMPORT joinrel_setup_hook_type joinrel_setup_hook
 

Typedef Documentation

◆ AppendPathInput

◆ build_simple_rel_hook_type

typedef void(* build_simple_rel_hook_type) (PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)

Definition at line 21 of file pathnode.h.

◆ joinrel_setup_hook_type

typedef void(* joinrel_setup_hook_type) (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)

Definition at line 42 of file pathnode.h.

Function Documentation

◆ add_partial_path()

void add_partial_path ( RelOptInfo parent_rel,
Path new_path 
)
extern

Definition at line 793 of file pathnode.c.

794{
795 bool accept_new = true; /* unless we find a superior old path */
796 int insert_at = 0; /* where to insert new item */
797 ListCell *p1;
798
799 /* Check for query cancel. */
801
802 /* Path to be added must be parallel safe. */
803 Assert(new_path->parallel_safe);
804
805 /* Relation should be OK for parallelism, too. */
806 Assert(parent_rel->consider_parallel);
807
808 /*
809 * As in add_path, throw out any paths which are dominated by the new
810 * path, but throw out the new path if some existing path dominates it.
811 */
812 foreach(p1, parent_rel->partial_pathlist)
813 {
814 Path *old_path = (Path *) lfirst(p1);
815 bool remove_old = false; /* unless new proves superior */
817
818 /* Compare pathkeys. */
819 keyscmp = compare_pathkeys(new_path->pathkeys, old_path->pathkeys);
820
821 /*
822 * Unless pathkeys are incompatible, see if one of the paths dominates
823 * the other (both in startup and total cost). It may happen that one
824 * path has lower startup cost, the other has lower total cost.
825 */
827 {
829
830 /*
831 * Do a fuzzy cost comparison with standard fuzziness limit.
832 */
835 if (costcmp == COSTS_BETTER1)
836 {
838 remove_old = true;
839 }
840 else if (costcmp == COSTS_BETTER2)
841 {
843 accept_new = false;
844 }
845 else if (costcmp == COSTS_EQUAL)
846 {
848 remove_old = true;
849 else if (keyscmp == PATHKEYS_BETTER2)
850 accept_new = false;
852 1.0000000001) == COSTS_BETTER1)
853 remove_old = true;
854 else
855 accept_new = false;
856 }
857 }
858
859 /*
860 * Remove current element from partial_pathlist if dominated by new.
861 */
862 if (remove_old)
863 {
864 parent_rel->partial_pathlist =
865 foreach_delete_current(parent_rel->partial_pathlist, p1);
867 }
868 else
869 {
870 /*
871 * new belongs after this old path if it has more disabled nodes
872 * or if it has the same number of nodes but a greater total cost
873 */
874 if (new_path->disabled_nodes > old_path->disabled_nodes ||
875 (new_path->disabled_nodes == old_path->disabled_nodes &&
876 new_path->total_cost >= old_path->total_cost))
878 }
879
880 /*
881 * If we found an old path that dominates new_path, we can quit
882 * scanning the partial_pathlist; we will not add new_path, and we
883 * assume new_path cannot dominate any later path.
884 */
885 if (!accept_new)
886 break;
887 }
888
889 if (accept_new)
890 {
891 /* Accept the new path: insert it at proper place */
892 parent_rel->partial_pathlist =
893 list_insert_nth(parent_rel->partial_pathlist, insert_at, new_path);
894 }
895 else
896 {
897 /* Reject and recycle the new path */
899 }
900}
#define Assert(condition)
Definition c.h:945
List * list_insert_nth(List *list, int pos, void *datum)
Definition list.c:439
void pfree(void *pointer)
Definition mcxt.c:1616
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
PathKeysComparison compare_pathkeys(List *keys1, List *keys2)
Definition pathkeys.c:304
static PathCostComparison compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
Definition pathnode.c:181
#define STD_FUZZ_FACTOR
Definition pathnode.c:47
PathCostComparison
Definition pathnode.c:35
@ COSTS_EQUAL
Definition pathnode.c:36
@ COSTS_BETTER1
Definition pathnode.c:37
@ COSTS_BETTER2
Definition pathnode.c:38
PathKeysComparison
Definition paths.h:219
@ PATHKEYS_BETTER2
Definition paths.h:222
@ PATHKEYS_BETTER1
Definition paths.h:221
@ PATHKEYS_DIFFERENT
Definition paths.h:223
#define lfirst(lc)
Definition pg_list.h:172
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:391
static int fb(int x)

References Assert, CHECK_FOR_INTERRUPTS, compare_path_costs_fuzzily(), compare_pathkeys(), COSTS_BETTER1, COSTS_BETTER2, COSTS_EQUAL, fb(), foreach_current_index, foreach_delete_current, lfirst, list_insert_nth(), PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, pfree(), and STD_FUZZ_FACTOR.

Referenced by add_paths_to_append_rel(), build_index_paths(), build_setop_child_paths(), create_partial_bitmap_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), create_partial_unique_paths(), create_plain_partial_paths(), create_tidscan_paths(), generate_grouped_paths(), grouping_planner(), set_subquery_pathlist(), try_partial_hashjoin_path(), try_partial_mergejoin_path(), and try_partial_nestloop_path().

◆ add_partial_path_precheck()

bool add_partial_path_precheck ( RelOptInfo parent_rel,
int  disabled_nodes,
Cost  startup_cost,
Cost  total_cost,
List pathkeys 
)
extern

Definition at line 912 of file pathnode.c.

914{
915 bool consider_startup = parent_rel->consider_startup;
916 ListCell *p1;
917
918 /*
919 * Our goal here is twofold. First, we want to find out whether this path
920 * is clearly inferior to some existing partial path. If so, we want to
921 * reject it immediately. Second, we want to find out whether this path
922 * is clearly superior to some existing partial path -- at least, modulo
923 * final cost computations. If so, we definitely want to consider it.
924 *
925 * Unlike add_path(), we never try to exit this loop early. This is
926 * because we expect partial_pathlist to be very short, and getting a
927 * definitive answer at this stage avoids the need to call
928 * add_path_precheck.
929 */
930 foreach(p1, parent_rel->partial_pathlist)
931 {
932 Path *old_path = (Path *) lfirst(p1);
935
936 /*
937 * First, compare costs and disabled nodes. This logic should be
938 * identical to compare_path_costs_fuzzily, except that one of the
939 * paths hasn't been created yet, and the fuzz factor is always
940 * STD_FUZZ_FACTOR.
941 */
942 if (unlikely(old_path->disabled_nodes != disabled_nodes))
943 {
944 if (disabled_nodes < old_path->disabled_nodes)
946 else
948 }
949 else if (total_cost > old_path->total_cost * STD_FUZZ_FACTOR)
950 {
951 if (consider_startup &&
952 old_path->startup_cost > startup_cost * STD_FUZZ_FACTOR)
954 else
956 }
957 else if (old_path->total_cost > total_cost * STD_FUZZ_FACTOR)
958 {
959 if (consider_startup &&
960 startup_cost > old_path->startup_cost * STD_FUZZ_FACTOR)
962 else
964 }
965 else if (startup_cost > old_path->startup_cost * STD_FUZZ_FACTOR)
967 else if (old_path->startup_cost > startup_cost * STD_FUZZ_FACTOR)
969 else
971
972 /*
973 * If one path wins on startup cost and the other on total cost, we
974 * can't say for sure which is better.
975 */
977 continue;
978
979 /*
980 * If the two paths have different pathkeys, we can't say for sure
981 * which is better.
982 */
983 keyscmp = compare_pathkeys(pathkeys, old_path->pathkeys);
985 continue;
986
987 /*
988 * If the existing path is cheaper and the pathkeys are equal or
989 * worse, the new path is not interesting.
990 */
992 return false;
993
994 /*
995 * If the new path is cheaper and the pathkeys are equal or better, it
996 * is definitely interesting.
997 */
999 return true;
1000 }
1001
1002 /*
1003 * This path is neither clearly inferior to an existing partial path nor
1004 * clearly good enough that it might replace one. Compare it to
1005 * non-parallel plans. If it loses even before accounting for the cost of
1006 * the Gather node, we should definitely reject it.
1007 */
1008 if (!add_path_precheck(parent_rel, disabled_nodes, startup_cost,
1009 total_cost, pathkeys, NULL))
1010 return false;
1011
1012 return true;
1013}
#define unlikely(x)
Definition c.h:432
@ COSTS_DIFFERENT
Definition pathnode.c:39
bool add_path_precheck(RelOptInfo *parent_rel, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
Definition pathnode.c:686

References add_path_precheck(), compare_pathkeys(), COSTS_BETTER1, COSTS_BETTER2, COSTS_DIFFERENT, COSTS_EQUAL, fb(), lfirst, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, STD_FUZZ_FACTOR, and unlikely.

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

Definition at line 459 of file pathnode.c.

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

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

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

◆ add_path_precheck()

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

Definition at line 686 of file pathnode.c.

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

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

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

◆ adjust_limit_rows_costs()

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

Definition at line 3848 of file pathnode.c.

3853{
3854 double input_rows = *rows;
3855 Cost input_startup_cost = *startup_cost;
3856 Cost input_total_cost = *total_cost;
3857
3858 if (offset_est != 0)
3859 {
3860 double offset_rows;
3861
3862 if (offset_est > 0)
3863 offset_rows = (double) offset_est;
3864 else
3866 if (offset_rows > *rows)
3867 offset_rows = *rows;
3868 if (input_rows > 0)
3869 *startup_cost +=
3872 *rows -= offset_rows;
3873 if (*rows < 1)
3874 *rows = 1;
3875 }
3876
3877 if (count_est != 0)
3878 {
3879 double count_rows;
3880
3881 if (count_est > 0)
3882 count_rows = (double) count_est;
3883 else
3885 if (count_rows > *rows)
3886 count_rows = *rows;
3887 if (input_rows > 0)
3888 *total_cost = *startup_cost +
3891 *rows = count_rows;
3892 if (*rows < 1)
3893 *rows = 1;
3894 }
3895}
double clamp_row_est(double nrows)
Definition costsize.c:214
double Cost
Definition nodes.h:261

References clamp_row_est(), and fb().

Referenced by create_limit_path(), and estimate_path_cost_size().

◆ apply_projection_to_path()

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

Definition at line 2696 of file pathnode.c.

2700{
2702
2703 /*
2704 * If given path can't project, we might need a Result node, so make a
2705 * separate ProjectionPath.
2706 */
2707 if (!is_projection_capable_path(path))
2708 return (Path *) create_projection_path(root, rel, path, target);
2709
2710 /*
2711 * We can just jam the desired tlist into the existing path, being sure to
2712 * update its cost estimates appropriately.
2713 */
2714 oldcost = path->pathtarget->cost;
2715 path->pathtarget = target;
2716
2717 path->startup_cost += target->cost.startup - oldcost.startup;
2718 path->total_cost += target->cost.startup - oldcost.startup +
2719 (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
2720
2721 /*
2722 * If the path happens to be a Gather or GatherMerge path, we'd like to
2723 * arrange for the subpath to return the required target list so that
2724 * workers can help project. But if there is something that is not
2725 * parallel-safe in the target expressions, then we can't.
2726 */
2727 if ((IsA(path, GatherPath) || IsA(path, GatherMergePath)) &&
2728 is_parallel_safe(root, (Node *) target->exprs))
2729 {
2730 /*
2731 * We always use create_projection_path here, even if the subpath is
2732 * projection-capable, so as to avoid modifying the subpath in place.
2733 * It seems unlikely at present that there could be any other
2734 * references to the subpath, but better safe than sorry.
2735 *
2736 * Note that we don't change the parallel path's cost estimates; it
2737 * might be appropriate to do so, to reflect the fact that the bulk of
2738 * the target evaluation will happen in workers.
2739 */
2740 if (IsA(path, GatherPath))
2741 {
2742 GatherPath *gpath = (GatherPath *) path;
2743
2744 gpath->subpath = (Path *)
2746 gpath->subpath->parent,
2747 gpath->subpath,
2748 target);
2749 }
2750 else
2751 {
2753
2754 gmpath->subpath = (Path *)
2756 gmpath->subpath->parent,
2757 gmpath->subpath,
2758 target);
2759 }
2760 }
2761 else if (path->parallel_safe &&
2762 !is_parallel_safe(root, (Node *) target->exprs))
2763 {
2764 /*
2765 * We're inserting a parallel-restricted target list into a path
2766 * currently marked parallel-safe, so we have to mark it as no longer
2767 * safe.
2768 */
2769 path->parallel_safe = false;
2770 }
2771
2772 return path;
2773}
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition clauses.c:764
bool is_projection_capable_path(Path *path)
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition pathnode.c:2587
tree ctl root
Definition radixtree.h:1857
Path * subpath
Definition pathnodes.h:2360
Definition nodes.h:135
List * exprs
Definition pathnodes.h:1866
QualCost cost
Definition pathnodes.h:1872
Cardinality rows
Definition pathnodes.h:1993
Cost startup_cost
Definition pathnodes.h:1995
Cost total_cost
Definition pathnodes.h:1996
bool parallel_safe
Definition pathnodes.h:1988
Cost per_tuple
Definition pathnodes.h:121
Cost startup
Definition pathnodes.h:120

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

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

◆ build_child_join_rel()

RelOptInfo * build_child_join_rel ( PlannerInfo root,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
RelOptInfo parent_joinrel,
List restrictlist,
SpecialJoinInfo sjinfo,
int  nappinfos,
AppendRelInfo **  appinfos 
)
extern

Definition at line 1026 of file relnode.c.

1030{
1031 RelOptInfo *joinrel = makeNode(RelOptInfo);
1032
1033 /* Only joins between "other" relations land here. */
1035
1036 /* The parent joinrel should have consider_partitionwise_join set. */
1037 Assert(parent_joinrel->consider_partitionwise_join);
1038
1040 joinrel->relids = adjust_child_relids(parent_joinrel->relids,
1041 nappinfos, appinfos);
1042 joinrel->rows = 0;
1043 /* cheap startup cost is interesting iff not all tuples to be retrieved */
1044 joinrel->consider_startup = (root->tuple_fraction > 0);
1045 joinrel->consider_param_startup = false;
1046 joinrel->consider_parallel = false;
1047 joinrel->pgs_mask = root->glob->default_pgs_mask;
1049 joinrel->pathlist = NIL;
1050 joinrel->ppilist = NIL;
1051 joinrel->partial_pathlist = NIL;
1052 joinrel->cheapest_startup_path = NULL;
1053 joinrel->cheapest_total_path = NULL;
1055 joinrel->direct_lateral_relids = NULL;
1056 joinrel->lateral_relids = NULL;
1057 joinrel->relid = 0; /* indicates not a baserel */
1058 joinrel->rtekind = RTE_JOIN;
1059 joinrel->min_attr = 0;
1060 joinrel->max_attr = 0;
1061 joinrel->attr_needed = NULL;
1062 joinrel->attr_widths = NULL;
1063 joinrel->notnullattnums = NULL;
1064 joinrel->nulling_relids = NULL;
1065 joinrel->lateral_vars = NIL;
1066 joinrel->lateral_referencers = NULL;
1067 joinrel->indexlist = NIL;
1068 joinrel->pages = 0;
1069 joinrel->tuples = 0;
1070 joinrel->allvisfrac = 0;
1071 joinrel->eclass_indexes = NULL;
1072 joinrel->subroot = NULL;
1073 joinrel->subplan_params = NIL;
1074 joinrel->amflags = 0;
1075 joinrel->serverid = InvalidOid;
1076 joinrel->userid = InvalidOid;
1077 joinrel->useridiscurrent = false;
1078 joinrel->fdwroutine = NULL;
1079 joinrel->fdw_private = NULL;
1080 joinrel->unique_rel = NULL;
1081 joinrel->unique_pathkeys = NIL;
1082 joinrel->unique_groupclause = NIL;
1083 joinrel->baserestrictinfo = NIL;
1084 joinrel->baserestrictcost.startup = 0;
1085 joinrel->baserestrictcost.per_tuple = 0;
1086 joinrel->joininfo = NIL;
1087 joinrel->has_eclass_joins = false;
1088 joinrel->consider_partitionwise_join = false; /* might get changed later */
1089 joinrel->agg_info = NULL;
1090 joinrel->grouped_rel = NULL;
1091 joinrel->parent = parent_joinrel;
1092 joinrel->top_parent = parent_joinrel->top_parent ? parent_joinrel->top_parent : parent_joinrel;
1093 joinrel->top_parent_relids = joinrel->top_parent->relids;
1094 joinrel->part_scheme = NULL;
1095 joinrel->nparts = -1;
1096 joinrel->boundinfo = NULL;
1097 joinrel->partbounds_merged = false;
1098 joinrel->partition_qual = NIL;
1099 joinrel->part_rels = NULL;
1100 joinrel->live_parts = NULL;
1101 joinrel->all_partrels = NULL;
1102 joinrel->partexprs = NULL;
1103 joinrel->nullable_partexprs = NULL;
1104
1105 /* Compute information relevant to foreign relations. */
1107
1108 /* Set up reltarget struct */
1110 nappinfos, appinfos);
1111
1112 /* Construct joininfo list. */
1114 (Node *) parent_joinrel->joininfo,
1115 nappinfos,
1116 appinfos);
1117
1118 /*
1119 * Lateral relids referred in child join will be same as that referred in
1120 * the parent relation.
1121 */
1122 joinrel->direct_lateral_relids = (Relids) bms_copy(parent_joinrel->direct_lateral_relids);
1123 joinrel->lateral_relids = (Relids) bms_copy(parent_joinrel->lateral_relids);
1124
1125 /*
1126 * If the parent joinrel has pending equivalence classes, so does the
1127 * child.
1128 */
1129 joinrel->has_eclass_joins = parent_joinrel->has_eclass_joins;
1130
1131 /* Child joinrel is parallel safe if parent is parallel safe. */
1132 joinrel->consider_parallel = parent_joinrel->consider_parallel;
1133
1134 /* Set estimates of the child-joinrel's size. */
1136 sjinfo, restrictlist);
1137
1138 /*
1139 * Allow a plugin to editorialize on the new joinrel's properties. Actions
1140 * might include altering the size estimate, clearing consider_parallel,
1141 * or adjusting pgs_mask. (However, note that clearing consider_parallel
1142 * would be better done in the parent joinrel rather than here.)
1143 */
1145 (*joinrel_setup_hook) (root, joinrel, outer_rel, inner_rel, sjinfo,
1146 restrictlist);
1147
1148 /* Is the join between partitions itself partitioned? */
1150 restrictlist);
1151
1152 /* We build the join only once. */
1153 Assert(!find_join_rel(root, joinrel->relids));
1154
1155 /* Add the relation to the PlannerInfo. */
1156 add_join_rel(root, joinrel);
1157
1158 /*
1159 * We might need EquivalenceClass members corresponding to the child join,
1160 * so that we can represent sort pathkeys for it. As with children of
1161 * baserels, we shouldn't need this unless there are relevant eclass joins
1162 * (implying that a merge join might be possible) or pathkeys to sort by.
1163 */
1164 if (joinrel->has_eclass_joins || has_useful_pathkeys(root, parent_joinrel))
1166 nappinfos, appinfos,
1167 parent_joinrel, joinrel);
1168
1169 return joinrel;
1170}
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition appendinfo.c:201
Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
Definition appendinfo.c:630
Bitmapset * bms_copy(const Bitmapset *a)
Definition bitmapset.c:122
void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition costsize.c:5571
void add_child_join_rel_equivalences(PlannerInfo *root, int nappinfos, AppendRelInfo **appinfos, RelOptInfo *parent_joinrel, RelOptInfo *child_joinrel)
#define makeNode(_type_)
Definition nodes.h:161
@ RTE_JOIN
bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel)
Definition pathkeys.c:2291
Bitmapset * Relids
Definition pathnodes.h:103
@ RELOPT_OTHER_JOINREL
Definition pathnodes.h:968
#define IS_OTHER_REL(rel)
Definition pathnodes.h:992
#define InvalidOid
static void build_joinrel_partition_info(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition relnode.c:2150
joinrel_setup_hook_type joinrel_setup_hook
Definition relnode.c:54
RelOptInfo * find_join_rel(PlannerInfo *root, Relids relids)
Definition relnode.c:657
static void build_child_join_reltarget(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, int nappinfos, AppendRelInfo **appinfos)
Definition relnode.c:2662
static void set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition relnode.c:719
static void add_join_rel(PlannerInfo *root, RelOptInfo *joinrel)
Definition relnode.c:757
List * baserestrictinfo
Definition pathnodes.h:1130
bool consider_param_startup
Definition pathnodes.h:1023
List * subplan_params
Definition pathnodes.h:1089
List * ppilist
Definition pathnodes.h:1039
bool useridiscurrent
Definition pathnodes.h:1103
uint32 amflags
Definition pathnodes.h:1093
List * joininfo
Definition pathnodes.h:1136
Bitmapset * notnullattnums
Definition pathnodes.h:1071
List * partition_qual
Definition pathnodes.h:1180
Relids relids
Definition pathnodes.h:1009
struct PathTarget * reltarget
Definition pathnodes.h:1033
Index relid
Definition pathnodes.h:1057
List * lateral_vars
Definition pathnodes.h:1075
struct RelAggInfo * agg_info
Definition pathnodes.h:1150
uint64 pgs_mask
Definition pathnodes.h:1027
List * unique_pathkeys
Definition pathnodes.h:1122
Cardinality tuples
Definition pathnodes.h:1084
bool consider_parallel
Definition pathnodes.h:1025
Relids top_parent_relids
Definition pathnodes.h:1162
bool partbounds_merged
Definition pathnodes.h:1178
BlockNumber pages
Definition pathnodes.h:1083
Relids lateral_relids
Definition pathnodes.h:1052
List * cheapest_parameterized_paths
Definition pathnodes.h:1043
List * pathlist
Definition pathnodes.h:1038
RelOptKind reloptkind
Definition pathnodes.h:1003
List * indexlist
Definition pathnodes.h:1079
Relids lateral_referencers
Definition pathnodes.h:1077
struct Path * cheapest_startup_path
Definition pathnodes.h:1041
QualCost baserestrictcost
Definition pathnodes.h:1132
struct Path * cheapest_total_path
Definition pathnodes.h:1042
List * unique_groupclause
Definition pathnodes.h:1124
struct RelOptInfo * grouped_rel
Definition pathnodes.h:1152
Bitmapset * eclass_indexes
Definition pathnodes.h:1087
Relids all_partrels
Definition pathnodes.h:1194
Relids direct_lateral_relids
Definition pathnodes.h:1050
bool has_eclass_joins
Definition pathnodes.h:1138
bool consider_startup
Definition pathnodes.h:1021
Bitmapset * live_parts
Definition pathnodes.h:1192
bool consider_partitionwise_join
Definition pathnodes.h:1144
List * partial_pathlist
Definition pathnodes.h:1040
PlannerInfo * subroot
Definition pathnodes.h:1088
AttrNumber max_attr
Definition pathnodes.h:1065
Relids nulling_relids
Definition pathnodes.h:1073
double allvisfrac
Definition pathnodes.h:1085
struct RelOptInfo * unique_rel
Definition pathnodes.h:1120
Cardinality rows
Definition pathnodes.h:1015
AttrNumber min_attr
Definition pathnodes.h:1063
RTEKind rtekind
Definition pathnodes.h:1061
PathTarget * create_empty_pathtarget(void)
Definition tlist.c:690

References add_child_join_rel_equivalences(), add_join_rel(), adjust_appendrel_attrs(), adjust_child_relids(), RelOptInfo::agg_info, RelOptInfo::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, Assert, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_copy(), build_child_join_reltarget(), build_joinrel_partition_info(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::consider_parallel, RelOptInfo::consider_param_startup, RelOptInfo::consider_partitionwise_join, RelOptInfo::consider_startup, create_empty_pathtarget(), RelOptInfo::direct_lateral_relids, RelOptInfo::eclass_indexes, fb(), find_join_rel(), RelOptInfo::grouped_rel, RelOptInfo::has_eclass_joins, has_useful_pathkeys(), RelOptInfo::indexlist, InvalidOid, IS_OTHER_REL, RelOptInfo::joininfo, joinrel_setup_hook, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, RelOptInfo::live_parts, makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, NIL, RelOptInfo::notnullattnums, RelOptInfo::nparts, RelOptInfo::nulling_relids, RelOptInfo::pages, RelOptInfo::partbounds_merged, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::pgs_mask, RelOptInfo::ppilist, RelOptInfo::relid, RelOptInfo::relids, RELOPT_OTHER_JOINREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, root, RelOptInfo::rows, RTE_JOIN, RelOptInfo::rtekind, RelOptInfo::serverid, set_foreign_rel_properties(), set_joinrel_size_estimates(), QualCost::startup, RelOptInfo::subplan_params, RelOptInfo::subroot, RelOptInfo::top_parent_relids, RelOptInfo::tuples, RelOptInfo::unique_groupclause, RelOptInfo::unique_pathkeys, RelOptInfo::unique_rel, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by try_partitionwise_join().

◆ build_grouped_rel()

RelOptInfo * build_grouped_rel ( PlannerInfo root,
RelOptInfo rel 
)
extern

Definition at line 499 of file relnode.c.

500{
501 RelOptInfo *grouped_rel;
502
503 grouped_rel = makeNode(RelOptInfo);
504 memcpy(grouped_rel, rel, sizeof(RelOptInfo));
505
506 /*
507 * clear path info
508 */
509 grouped_rel->pathlist = NIL;
510 grouped_rel->ppilist = NIL;
511 grouped_rel->partial_pathlist = NIL;
512 grouped_rel->cheapest_startup_path = NULL;
513 grouped_rel->cheapest_total_path = NULL;
514 grouped_rel->cheapest_parameterized_paths = NIL;
515
516 /*
517 * clear partition info
518 */
519 grouped_rel->part_scheme = NULL;
520 grouped_rel->nparts = -1;
521 grouped_rel->boundinfo = NULL;
522 grouped_rel->partbounds_merged = false;
523 grouped_rel->partition_qual = NIL;
524 grouped_rel->part_rels = NULL;
525 grouped_rel->live_parts = NULL;
526 grouped_rel->all_partrels = NULL;
527 grouped_rel->partexprs = NULL;
528 grouped_rel->nullable_partexprs = NULL;
529 grouped_rel->consider_partitionwise_join = false;
530
531 /*
532 * clear size estimates
533 */
534 grouped_rel->rows = 0;
535
536 return grouped_rel;
537}

References RelOptInfo::all_partrels, RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::consider_partitionwise_join, fb(), RelOptInfo::live_parts, makeNode, NIL, RelOptInfo::nparts, RelOptInfo::partbounds_merged, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, RelOptInfo::ppilist, and RelOptInfo::rows.

Referenced by build_simple_grouped_rel(), and make_grouped_join_rel().

◆ build_join_rel()

RelOptInfo * build_join_rel ( PlannerInfo root,
Relids  joinrelids,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
SpecialJoinInfo sjinfo,
List pushed_down_joins,
List **  restrictlist_ptr 
)
extern

Definition at line 795 of file relnode.c.

802{
803 RelOptInfo *joinrel;
804 List *restrictlist;
805
806 /* This function should be used only for join between parents. */
808
809 /*
810 * See if we already have a joinrel for this set of base rels.
811 */
812 joinrel = find_join_rel(root, joinrelids);
813
814 if (joinrel)
815 {
816 /*
817 * Yes, so we only need to figure the restrictlist for this particular
818 * pair of component relations.
819 */
822 joinrel,
823 outer_rel,
824 inner_rel,
825 sjinfo);
826 return joinrel;
827 }
828
829 /*
830 * Nope, so make one.
831 */
832 joinrel = makeNode(RelOptInfo);
833 joinrel->reloptkind = RELOPT_JOINREL;
834 joinrel->relids = bms_copy(joinrelids);
835 joinrel->rows = 0;
836 /* cheap startup cost is interesting iff not all tuples to be retrieved */
837 joinrel->consider_startup = (root->tuple_fraction > 0);
838 joinrel->consider_param_startup = false;
839 joinrel->consider_parallel = false;
840 joinrel->pgs_mask = root->glob->default_pgs_mask;
842 joinrel->pathlist = NIL;
843 joinrel->ppilist = NIL;
844 joinrel->partial_pathlist = NIL;
845 joinrel->cheapest_startup_path = NULL;
846 joinrel->cheapest_total_path = NULL;
848 /* init direct_lateral_relids from children; we'll finish it up below */
849 joinrel->direct_lateral_relids =
850 bms_union(outer_rel->direct_lateral_relids,
851 inner_rel->direct_lateral_relids);
854 joinrel->relid = 0; /* indicates not a baserel */
855 joinrel->rtekind = RTE_JOIN;
856 joinrel->min_attr = 0;
857 joinrel->max_attr = 0;
858 joinrel->attr_needed = NULL;
859 joinrel->attr_widths = NULL;
860 joinrel->notnullattnums = NULL;
861 joinrel->nulling_relids = NULL;
862 joinrel->lateral_vars = NIL;
863 joinrel->lateral_referencers = NULL;
864 joinrel->indexlist = NIL;
865 joinrel->statlist = NIL;
866 joinrel->pages = 0;
867 joinrel->tuples = 0;
868 joinrel->allvisfrac = 0;
869 joinrel->eclass_indexes = NULL;
870 joinrel->subroot = NULL;
871 joinrel->subplan_params = NIL;
872 joinrel->rel_parallel_workers = -1;
873 joinrel->amflags = 0;
874 joinrel->serverid = InvalidOid;
875 joinrel->userid = InvalidOid;
876 joinrel->useridiscurrent = false;
877 joinrel->fdwroutine = NULL;
878 joinrel->fdw_private = NULL;
879 joinrel->unique_for_rels = NIL;
880 joinrel->non_unique_for_rels = NIL;
881 joinrel->unique_rel = NULL;
882 joinrel->unique_pathkeys = NIL;
883 joinrel->unique_groupclause = NIL;
884 joinrel->baserestrictinfo = NIL;
885 joinrel->baserestrictcost.startup = 0;
886 joinrel->baserestrictcost.per_tuple = 0;
888 joinrel->joininfo = NIL;
889 joinrel->has_eclass_joins = false;
890 joinrel->consider_partitionwise_join = false; /* might get changed later */
891 joinrel->agg_info = NULL;
892 joinrel->grouped_rel = NULL;
893 joinrel->parent = NULL;
894 joinrel->top_parent = NULL;
895 joinrel->top_parent_relids = NULL;
896 joinrel->part_scheme = NULL;
897 joinrel->nparts = -1;
898 joinrel->boundinfo = NULL;
899 joinrel->partbounds_merged = false;
900 joinrel->partition_qual = NIL;
901 joinrel->part_rels = NULL;
902 joinrel->live_parts = NULL;
903 joinrel->all_partrels = NULL;
904 joinrel->partexprs = NULL;
905 joinrel->nullable_partexprs = NULL;
906
907 /* Compute information relevant to the foreign relations. */
909
910 /*
911 * Fill the joinrel's tlist with just the Vars and PHVs that need to be
912 * output from this join (ie, are needed for higher joinclauses or final
913 * output).
914 *
915 * NOTE: the tlist order for a join rel will depend on which pair of outer
916 * and inner rels we first try to build it from. But the contents should
917 * be the same regardless.
918 */
920 (sjinfo->jointype == JOIN_FULL));
922 (sjinfo->jointype != JOIN_INNER));
924
925 /*
926 * add_placeholders_to_joinrel also took care of adding the ph_lateral
927 * sets of any PlaceHolderVars computed here to direct_lateral_relids, so
928 * now we can finish computing that. This is much like the computation of
929 * the transitively-closed lateral_relids in min_join_parameterization,
930 * except that here we *do* have to consider the added PHVs.
931 */
932 joinrel->direct_lateral_relids =
933 bms_del_members(joinrel->direct_lateral_relids, joinrel->relids);
934
935 /*
936 * Construct restrict and join clause lists for the new joinrel. (The
937 * caller might or might not need the restrictlist, but I need it anyway
938 * for set_joinrel_size_estimates().)
939 */
940 restrictlist = build_joinrel_restrictlist(root, joinrel,
942 sjinfo);
944 *restrictlist_ptr = restrictlist;
946
947 /*
948 * This is also the right place to check whether the joinrel has any
949 * pending EquivalenceClass joins.
950 */
952
953 /*
954 * Set estimates of the joinrel's size.
955 */
957 sjinfo, restrictlist);
958
959 /*
960 * Set the consider_parallel flag if this joinrel could potentially be
961 * scanned within a parallel worker. If this flag is false for either
962 * inner_rel or outer_rel, then it must be false for the joinrel also.
963 * Even if both are true, there might be parallel-restricted expressions
964 * in the targetlist or quals.
965 *
966 * Note that if there are more than two rels in this relation, they could
967 * be divided between inner_rel and outer_rel in any arbitrary way. We
968 * assume this doesn't matter, because we should hit all the same baserels
969 * and joinclauses while building up to this joinrel no matter which we
970 * take; therefore, we should make the same decision here however we get
971 * here.
972 */
973 if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
974 is_parallel_safe(root, (Node *) restrictlist) &&
975 is_parallel_safe(root, (Node *) joinrel->reltarget->exprs))
976 joinrel->consider_parallel = true;
977
978 /*
979 * Allow a plugin to editorialize on the new joinrel's properties. Actions
980 * might include altering the size estimate, clearing consider_parallel,
981 * or adjusting pgs_mask.
982 */
984 (*joinrel_setup_hook) (root, joinrel, outer_rel, inner_rel, sjinfo,
985 restrictlist);
986
987 /* Store the partition information. */
989 restrictlist);
990
991 /* Add the joinrel to the PlannerInfo. */
992 add_join_rel(root, joinrel);
993
994 /*
995 * Also, if dynamic-programming join search is active, add the new joinrel
996 * to the appropriate sublist. Note: you might think the Assert on number
997 * of members should be for equality, but some of the level 1 rels might
998 * have been joinrels already, so we can only assert <=.
999 */
1000 if (root->join_rel_level)
1001 {
1002 Assert(root->join_cur_level > 0);
1003 Assert(root->join_cur_level <= bms_num_members(joinrel->relids));
1004 root->join_rel_level[root->join_cur_level] =
1005 lappend(root->join_rel_level[root->join_cur_level], joinrel);
1006 }
1007
1008 return joinrel;
1009}
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1145
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:744
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:251
bool has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
List * lappend(List *list, void *datum)
Definition list.c:339
@ JOIN_FULL
Definition nodes.h:305
@ JOIN_INNER
Definition nodes.h:303
@ RELOPT_JOINREL
Definition pathnodes.h:966
void add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel, SpecialJoinInfo *sjinfo, List *pushed_down_joins, bool can_null)
Definition relnode.c:1259
Relids min_join_parameterization(PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition relnode.c:1181
static List * build_joinrel_restrictlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
Definition relnode.c:1444
static void build_joinrel_joinlist(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition relnode.c:1481
List * statlist
Definition pathnodes.h:1081
List * unique_for_rels
Definition pathnodes.h:1112
List * non_unique_for_rels
Definition pathnodes.h:1114
int rel_parallel_workers
Definition pathnodes.h:1091
Index baserestrict_min_security
Definition pathnodes.h:1134
JoinType jointype
Definition pathnodes.h:3217

References add_join_rel(), add_placeholders_to_joinrel(), RelOptInfo::agg_info, RelOptInfo::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, Assert, RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_copy(), bms_del_members(), bms_num_members(), bms_union(), build_joinrel_joinlist(), build_joinrel_partition_info(), build_joinrel_restrictlist(), build_joinrel_tlist(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::consider_parallel, RelOptInfo::consider_param_startup, RelOptInfo::consider_partitionwise_join, RelOptInfo::consider_startup, create_empty_pathtarget(), RelOptInfo::direct_lateral_relids, RelOptInfo::eclass_indexes, PathTarget::exprs, fb(), find_join_rel(), RelOptInfo::grouped_rel, RelOptInfo::has_eclass_joins, has_relevant_eclass_joinclause(), RelOptInfo::indexlist, InvalidOid, IS_OTHER_REL, is_parallel_safe(), JOIN_FULL, JOIN_INNER, RelOptInfo::joininfo, joinrel_setup_hook, SpecialJoinInfo::jointype, lappend(), RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, RelOptInfo::live_parts, makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, min_join_parameterization(), NIL, RelOptInfo::non_unique_for_rels, RelOptInfo::notnullattnums, RelOptInfo::nparts, RelOptInfo::nulling_relids, RelOptInfo::pages, RelOptInfo::partbounds_merged, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::pgs_mask, RelOptInfo::ppilist, RelOptInfo::rel_parallel_workers, RelOptInfo::relid, RelOptInfo::relids, RELOPT_JOINREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, root, RelOptInfo::rows, RTE_JOIN, RelOptInfo::rtekind, RelOptInfo::serverid, set_foreign_rel_properties(), set_joinrel_size_estimates(), QualCost::startup, RelOptInfo::statlist, RelOptInfo::subplan_params, RelOptInfo::subroot, RelOptInfo::top_parent_relids, RelOptInfo::tuples, RelOptInfo::unique_for_rels, RelOptInfo::unique_groupclause, RelOptInfo::unique_pathkeys, RelOptInfo::unique_rel, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by make_join_rel().

◆ build_simple_grouped_rel()

RelOptInfo * build_simple_grouped_rel ( PlannerInfo root,
RelOptInfo rel 
)
extern

Definition at line 448 of file relnode.c.

449{
450 RelOptInfo *grouped_rel;
451 RelAggInfo *agg_info;
452
453 /*
454 * We should have available aggregate expressions and grouping
455 * expressions, otherwise we cannot reach here.
456 */
457 Assert(root->agg_clause_list != NIL);
458 Assert(root->group_expr_list != NIL);
459
460 /* nothing to do for dummy rel */
461 if (IS_DUMMY_REL(rel))
462 return NULL;
463
464 /*
465 * Prepare the information needed to create grouped paths for this simple
466 * relation.
467 */
468 agg_info = create_rel_agg_info(root, rel, true);
469 if (agg_info == NULL)
470 return NULL;
471
472 /*
473 * If grouped paths for the given simple relation are not considered
474 * useful, skip building the grouped relation.
475 */
476 if (!agg_info->agg_useful)
477 return NULL;
478
479 /* Track the set of relids at which partial aggregation is applied */
480 agg_info->apply_agg_at = bms_copy(rel->relids);
481
482 /* build the grouped relation */
483 grouped_rel = build_grouped_rel(root, rel);
484 grouped_rel->reltarget = agg_info->target;
485 grouped_rel->rows = agg_info->grouped_rows;
486 grouped_rel->agg_info = agg_info;
487
488 rel->grouped_rel = grouped_rel;
489
490 return grouped_rel;
491}
#define IS_DUMMY_REL(r)
Definition pathnodes.h:2287
RelOptInfo * build_grouped_rel(PlannerInfo *root, RelOptInfo *rel)
Definition relnode.c:499
RelAggInfo * create_rel_agg_info(PlannerInfo *root, RelOptInfo *rel, bool calculate_grouped_rows)
Definition relnode.c:2691
Relids apply_agg_at
Definition pathnodes.h:1290
bool agg_useful
Definition pathnodes.h:1296
Cardinality grouped_rows
Definition pathnodes.h:1293
struct PathTarget * target
Definition pathnodes.h:1279

References RelOptInfo::agg_info, RelAggInfo::agg_useful, RelAggInfo::apply_agg_at, Assert, bms_copy(), build_grouped_rel(), create_rel_agg_info(), fb(), RelOptInfo::grouped_rel, RelAggInfo::grouped_rows, IS_DUMMY_REL, NIL, RelOptInfo::relids, RelOptInfo::reltarget, root, RelOptInfo::rows, and RelAggInfo::target.

Referenced by setup_simple_grouped_rels().

◆ build_simple_rel()

RelOptInfo * build_simple_rel ( PlannerInfo root,
int  relid,
RelOptInfo parent 
)
extern

Definition at line 212 of file relnode.c.

213{
214 RelOptInfo *rel;
216
217 /* Rel should not exist already */
218 Assert(relid > 0 && relid < root->simple_rel_array_size);
219 if (root->simple_rel_array[relid] != NULL)
220 elog(ERROR, "rel %d already exists", relid);
221
222 /* Fetch RTE for relation */
223 rte = root->simple_rte_array[relid];
224 Assert(rte != NULL);
225
226 rel = makeNode(RelOptInfo);
228 rel->relids = bms_make_singleton(relid);
229 rel->rows = 0;
230 /* cheap startup cost is interesting iff not all tuples to be retrieved */
231 rel->consider_startup = (root->tuple_fraction > 0);
232 rel->consider_param_startup = false; /* might get changed later */
233 rel->consider_parallel = false; /* might get changed later */
234 rel->pgs_mask = root->glob->default_pgs_mask;
236 rel->pathlist = NIL;
237 rel->ppilist = NIL;
238 rel->partial_pathlist = NIL;
242 rel->relid = relid;
243 rel->rtekind = rte->rtekind;
244 /* min_attr, max_attr, attr_needed, attr_widths are set below */
245 rel->notnullattnums = NULL;
246 rel->lateral_vars = NIL;
247 rel->indexlist = NIL;
248 rel->statlist = NIL;
249 rel->pages = 0;
250 rel->tuples = 0;
251 rel->allvisfrac = 0;
252 rel->eclass_indexes = NULL;
253 rel->subroot = NULL;
254 rel->subplan_params = NIL;
255 rel->rel_parallel_workers = -1; /* set up in get_relation_info */
256 rel->amflags = 0;
257 rel->serverid = InvalidOid;
258 if (rte->rtekind == RTE_RELATION)
259 {
260 Assert(parent == NULL ||
261 parent->rtekind == RTE_RELATION ||
262 parent->rtekind == RTE_SUBQUERY);
263
264 /*
265 * For any RELATION rte, we need a userid with which to check
266 * permission access. Baserels simply use their own
267 * RTEPermissionInfo's checkAsUser.
268 *
269 * For otherrels normally there's no RTEPermissionInfo, so we use the
270 * parent's, which normally has one. The exceptional case is that the
271 * parent is a subquery, in which case the otherrel will have its own.
272 */
273 if (rel->reloptkind == RELOPT_BASEREL ||
275 parent->rtekind == RTE_SUBQUERY))
276 {
278
279 perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
280 rel->userid = perminfo->checkAsUser;
281 }
282 else
283 rel->userid = parent->userid;
284 }
285 else
286 rel->userid = InvalidOid;
287 rel->useridiscurrent = false;
288 rel->fdwroutine = NULL;
289 rel->fdw_private = NULL;
290 rel->unique_for_rels = NIL;
292 rel->unique_rel = NULL;
293 rel->unique_pathkeys = NIL;
294 rel->unique_groupclause = NIL;
295 rel->baserestrictinfo = NIL;
296 rel->baserestrictcost.startup = 0;
299 rel->joininfo = NIL;
300 rel->has_eclass_joins = false;
301 rel->consider_partitionwise_join = false; /* might get changed later */
302 rel->agg_info = NULL;
303 rel->grouped_rel = NULL;
304 rel->part_scheme = NULL;
305 rel->nparts = -1;
306 rel->boundinfo = NULL;
307 rel->partbounds_merged = false;
308 rel->partition_qual = NIL;
309 rel->part_rels = NULL;
310 rel->live_parts = NULL;
311 rel->all_partrels = NULL;
312 rel->partexprs = NULL;
313 rel->nullable_partexprs = NULL;
314
315 /*
316 * Pass assorted information down the inheritance hierarchy.
317 */
318 if (parent)
319 {
320 /* We keep back-links to immediate parent and topmost parent. */
321 rel->parent = parent;
322 rel->top_parent = parent->top_parent ? parent->top_parent : parent;
323 rel->top_parent_relids = rel->top_parent->relids;
324
325 /*
326 * A child rel is below the same outer joins as its parent. (We
327 * presume this info was already calculated for the parent.)
328 */
329 rel->nulling_relids = parent->nulling_relids;
330
331 /*
332 * Also propagate lateral-reference information from appendrel parent
333 * rels to their child rels. We intentionally give each child rel the
334 * same minimum parameterization, even though it's quite possible that
335 * some don't reference all the lateral rels. This is because any
336 * append path for the parent will have to have the same
337 * parameterization for every child anyway, and there's no value in
338 * forcing extra reparameterize_path() calls. Similarly, a lateral
339 * reference to the parent prevents use of otherwise-movable join rels
340 * for each child.
341 *
342 * It's possible for child rels to have their own children, in which
343 * case the topmost parent's lateral info propagates all the way down.
344 */
346 rel->lateral_relids = parent->lateral_relids;
348 }
349 else
350 {
351 rel->parent = NULL;
352 rel->top_parent = NULL;
353 rel->top_parent_relids = NULL;
354 rel->nulling_relids = NULL;
356 rel->lateral_relids = NULL;
358 }
359
360 /* Check type of rtable entry */
361 switch (rte->rtekind)
362 {
363 case RTE_RELATION:
364 /* Table --- retrieve statistics from the system catalogs */
365 get_relation_info(root, rte->relid, rte->inh, rel);
366 break;
367 case RTE_SUBQUERY:
368 case RTE_FUNCTION:
369 case RTE_TABLEFUNC:
370 case RTE_VALUES:
371 case RTE_CTE:
373
374 /*
375 * Subquery, function, tablefunc, values list, CTE, or ENR --- set
376 * up attr range and arrays
377 *
378 * Note: 0 is included in range to support whole-row Vars
379 */
380 rel->min_attr = 0;
381 rel->max_attr = list_length(rte->eref->colnames);
382 rel->attr_needed = (Relids *)
383 palloc0_array(Relids, rel->max_attr - rel->min_attr + 1);
384 rel->attr_widths = (int32 *)
385 palloc0_array(int32, rel->max_attr - rel->min_attr + 1);
386 break;
387 case RTE_RESULT:
388 /* RTE_RESULT has no columns, nor could it have whole-row Var */
389 rel->min_attr = 0;
390 rel->max_attr = -1;
391 rel->attr_needed = NULL;
392 rel->attr_widths = NULL;
393 break;
394 default:
395 elog(ERROR, "unrecognized RTE kind: %d",
396 (int) rte->rtekind);
397 break;
398 }
399
400 /*
401 * Allow a plugin to editorialize on the new RelOptInfo. This could
402 * involve editorializing on the information which get_relation_info
403 * obtained from the catalogs, such as altering the assumed relation size,
404 * removing an index, or adding a hypothetical index to the indexlist.
405 *
406 * An extension can also modify rel->pgs_mask here to control path
407 * generation.
408 */
410 (*build_simple_rel_hook) (root, rel, rte);
411
412 /*
413 * Apply the parent's quals to the child, with appropriate substitution of
414 * variables. If any resulting clause is reduced to constant FALSE or
415 * NULL, apply_child_basequals returns false to indicate that scanning
416 * this relation won't yield any rows. In this case, we mark the child as
417 * dummy right away. (We must do this immediately so that pruning works
418 * correctly when recursing in expand_partitioned_rtentry.)
419 */
420 if (parent)
421 {
422 AppendRelInfo *appinfo = root->append_rel_array[relid];
423
424 Assert(appinfo != NULL);
425 if (!apply_child_basequals(root, parent, rel, rte, appinfo))
426 {
427 /*
428 * A restriction clause reduced to constant FALSE or NULL after
429 * substitution. Mark the child as dummy so that it need not be
430 * scanned.
431 */
432 mark_dummy_rel(rel);
433 }
434 }
435
436 /* Save the finished struct in the query's simple_rel_array */
437 root->simple_rel_array[relid] = rel;
438
439 return rel;
440}
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:216
int32_t int32
Definition c.h:614
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define palloc0_array(type, count)
Definition fe_memutils.h:77
bool apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, RangeTblEntry *childRTE, AppendRelInfo *appinfo)
Definition inherit.c:837
void mark_dummy_rel(RelOptInfo *rel)
Definition joinrels.c:1513
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_CTE
@ RTE_NAMEDTUPLESTORE
@ RTE_VALUES
@ RTE_SUBQUERY
@ RTE_RESULT
@ RTE_FUNCTION
@ RTE_TABLEFUNC
@ RTE_RELATION
@ RELOPT_BASEREL
Definition pathnodes.h:965
@ RELOPT_OTHER_MEMBER_REL
Definition pathnodes.h:967
static int list_length(const List *l)
Definition pg_list.h:152
void get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, RelOptInfo *rel)
Definition plancat.c:121
build_simple_rel_hook_type build_simple_rel_hook
Definition relnode.c:51

References RelOptInfo::agg_info, RelOptInfo::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, apply_child_basequals(), Assert, RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_make_singleton(), build_simple_rel_hook, RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::consider_parallel, RelOptInfo::consider_param_startup, RelOptInfo::consider_partitionwise_join, RelOptInfo::consider_startup, create_empty_pathtarget(), RelOptInfo::direct_lateral_relids, RelOptInfo::eclass_indexes, elog, ERROR, fb(), get_relation_info(), getRTEPermissionInfo(), RelOptInfo::grouped_rel, RelOptInfo::has_eclass_joins, RelOptInfo::indexlist, InvalidOid, RelOptInfo::joininfo, RelOptInfo::lateral_referencers, RelOptInfo::lateral_relids, RelOptInfo::lateral_vars, list_length(), RelOptInfo::live_parts, makeNode, mark_dummy_rel(), RelOptInfo::max_attr, RelOptInfo::min_attr, NIL, RelOptInfo::non_unique_for_rels, RelOptInfo::notnullattnums, RelOptInfo::nparts, RelOptInfo::nulling_relids, RelOptInfo::pages, palloc0_array, RelOptInfo::partbounds_merged, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::pgs_mask, RelOptInfo::ppilist, RelOptInfo::rel_parallel_workers, RelOptInfo::relid, RelOptInfo::relids, RELOPT_BASEREL, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, RelOptInfo::reltarget, root, RelOptInfo::rows, RTE_CTE, RTE_FUNCTION, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RelOptInfo::rtekind, RelOptInfo::serverid, QualCost::startup, RelOptInfo::statlist, RelOptInfo::subplan_params, RelOptInfo::subroot, RelOptInfo::top_parent_relids, RelOptInfo::tuples, RelOptInfo::unique_for_rels, RelOptInfo::unique_groupclause, RelOptInfo::unique_pathkeys, RelOptInfo::unique_rel, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by add_base_rels_to_query(), expand_appendrel_subquery(), expand_inherited_rtentry(), expand_partitioned_rtentry(), plan_cluster_use_sort(), plan_create_index_workers(), query_planner(), and recurse_set_operations().

◆ calc_nestloop_required_outer()

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

Definition at line 2277 of file pathnode.c.

2281{
2283
2284 /* inner_path can require rels from outer path, but not vice versa */
2286 /* easy case if inner path is not parameterized */
2287 if (!inner_paramrels)
2288 return bms_copy(outer_paramrels);
2289 /* else, form the union ... */
2291 /* ... and remove any mention of now-satisfied outer rels */
2293 outerrelids);
2294 return required_outer;
2295}
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:575

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

Referenced by try_nestloop_path().

◆ calc_non_nestloop_required_outer()

Relids calc_non_nestloop_required_outer ( Path outer_path,
Path inner_path 
)
extern

Definition at line 2304 of file pathnode.c.

2305{
2309 Relids outerrelids PG_USED_FOR_ASSERTS_ONLY;
2311
2312 /*
2313 * Any parameterization of the input paths refers to topmost parents of
2314 * the relevant relations, because reparameterize_path_by_child() hasn't
2315 * been called yet. So we must consider topmost parents of the relations
2316 * being joined, too, while checking for disallowed parameterization
2317 * cases.
2318 */
2319 if (inner_path->parent->top_parent_relids)
2320 innerrelids = inner_path->parent->top_parent_relids;
2321 else
2322 innerrelids = inner_path->parent->relids;
2323
2324 if (outer_path->parent->top_parent_relids)
2325 outerrelids = outer_path->parent->top_parent_relids;
2326 else
2327 outerrelids = outer_path->parent->relids;
2328
2329 /* neither path can require rels from the other */
2331 Assert(!bms_overlap(inner_paramrels, outerrelids));
2332 /* form the union ... */
2334 /* we do not need an explicit test for empty; bms_union gets it right */
2335 return required_outer;
2336}
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:243

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

Referenced by try_hashjoin_path(), and try_mergejoin_path().

◆ compare_fractional_path_costs()

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

Definition at line 123 of file pathnode.c.

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

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

Referenced by get_cheapest_fractional_path(), and get_cheapest_fractional_path_for_pathkeys().

◆ compare_path_costs()

int compare_path_costs ( Path path1,
Path path2,
CostSelector  criterion 
)
extern

Definition at line 68 of file pathnode.c.

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

References fb(), STARTUP_COST, and unlikely.

Referenced by append_startup_cost_compare(), append_total_cost_compare(), compare_fractional_path_costs(), generate_mergejoin_paths(), get_cheapest_parameterized_child_path(), get_cheapest_path_for_pathkeys(), and set_cheapest().

◆ 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 
)
extern

Definition at line 3057 of file pathnode.c.

3067{
3069
3070 pathnode->path.pathtype = T_Agg;
3071 pathnode->path.parent = rel;
3072 pathnode->path.pathtarget = target;
3073 pathnode->path.param_info = subpath->param_info;
3074 pathnode->path.parallel_aware = false;
3075 pathnode->path.parallel_safe = rel->consider_parallel &&
3076 subpath->parallel_safe;
3077 pathnode->path.parallel_workers = subpath->parallel_workers;
3078
3079 if (aggstrategy == AGG_SORTED)
3080 {
3081 /*
3082 * Attempt to preserve the order of the subpath. Additional pathkeys
3083 * may have been added in adjust_group_pathkeys_for_groupagg() to
3084 * support ORDER BY / DISTINCT aggregates. Pathkeys added there
3085 * belong to columns within the aggregate function, so we must strip
3086 * these additional pathkeys off as those columns are unavailable
3087 * above the aggregate node.
3088 */
3089 if (list_length(subpath->pathkeys) > root->num_groupby_pathkeys)
3090 pathnode->path.pathkeys = list_copy_head(subpath->pathkeys,
3091 root->num_groupby_pathkeys);
3092 else
3093 pathnode->path.pathkeys = subpath->pathkeys; /* preserves order */
3094 }
3095 else
3096 pathnode->path.pathkeys = NIL; /* output is unordered */
3097
3098 pathnode->subpath = subpath;
3099
3100 pathnode->aggstrategy = aggstrategy;
3101 pathnode->aggsplit = aggsplit;
3102 pathnode->numGroups = numGroups;
3103 pathnode->transitionSpace = aggcosts ? aggcosts->transitionSpace : 0;
3104 pathnode->groupClause = groupClause;
3105 pathnode->qual = qual;
3106
3107 cost_agg(&pathnode->path, root,
3108 aggstrategy, aggcosts,
3109 list_length(groupClause), numGroups,
3110 qual,
3111 subpath->disabled_nodes,
3112 subpath->startup_cost, subpath->total_cost,
3113 subpath->rows, subpath->pathtarget->width);
3114
3115 /* add tlist eval cost for each output row */
3116 pathnode->path.startup_cost += target->cost.startup;
3117 pathnode->path.total_cost += target->cost.startup +
3118 target->cost.per_tuple * pathnode->path.rows;
3119
3120 return pathnode;
3121}
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:2788
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

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

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

◆ create_append_path()

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

Definition at line 1352 of file pathnode.c.

1358{
1360 ListCell *l;
1361
1362 Assert(!parallel_aware || parallel_workers > 0);
1363
1364 pathnode->child_append_relid_sets = input.child_append_relid_sets;
1365 pathnode->path.pathtype = T_Append;
1366 pathnode->path.parent = rel;
1367 pathnode->path.pathtarget = rel->reltarget;
1368
1369 /*
1370 * If this is for a baserel (not a join or non-leaf partition), we prefer
1371 * to apply get_baserel_parampathinfo to construct a full ParamPathInfo
1372 * for the path. This supports building a Memoize path atop this path,
1373 * and if this is a partitioned table the info may be useful for run-time
1374 * pruning (cf make_partition_pruneinfo()).
1375 *
1376 * However, if we don't have "root" then that won't work and we fall back
1377 * on the simpler get_appendrel_parampathinfo. There's no point in doing
1378 * the more expensive thing for a dummy path, either.
1379 */
1380 if (rel->reloptkind == RELOPT_BASEREL && root && input.subpaths != NIL)
1381 pathnode->path.param_info = get_baserel_parampathinfo(root,
1382 rel,
1384 else
1385 pathnode->path.param_info = get_appendrel_parampathinfo(rel,
1387
1388 pathnode->path.parallel_aware = parallel_aware;
1389 pathnode->path.parallel_safe = rel->consider_parallel;
1390 pathnode->path.parallel_workers = parallel_workers;
1391 pathnode->path.pathkeys = pathkeys;
1392
1393 /*
1394 * For parallel append, non-partial paths are sorted by descending total
1395 * costs. That way, the total time to finish all non-partial paths is
1396 * minimized. Also, the partial paths are sorted by descending startup
1397 * costs. There may be some paths that require to do startup work by a
1398 * single worker. In such case, it's better for workers to choose the
1399 * expensive ones first, whereas the leader should choose the cheapest
1400 * startup plan.
1401 */
1402 if (pathnode->path.parallel_aware)
1403 {
1404 /*
1405 * We mustn't fiddle with the order of subpaths when the Append has
1406 * pathkeys. The order they're listed in is critical to keeping the
1407 * pathkeys valid.
1408 */
1409 Assert(pathkeys == NIL);
1410
1412 list_sort(input.partial_subpaths, append_startup_cost_compare);
1413 }
1414 pathnode->first_partial_path = list_length(input.subpaths);
1415 pathnode->subpaths = list_concat(input.subpaths, input.partial_subpaths);
1416
1417 /*
1418 * Apply query-wide LIMIT if known and path is for sole base relation.
1419 * (Handling this at this low level is a bit klugy.)
1420 */
1421 if (root != NULL && bms_equal(rel->relids, root->all_query_rels))
1422 pathnode->limit_tuples = root->limit_tuples;
1423 else
1424 pathnode->limit_tuples = -1.0;
1425
1426 foreach(l, pathnode->subpaths)
1427 {
1428 Path *subpath = (Path *) lfirst(l);
1429
1430 pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1431 subpath->parallel_safe;
1432
1433 /* All child paths must have same parameterization */
1435 }
1436
1437 Assert(!parallel_aware || pathnode->path.parallel_safe);
1438
1439 /*
1440 * If there's exactly one child path then the output of the Append is
1441 * necessarily ordered the same as the child's, so we can inherit the
1442 * child's pathkeys if any, overriding whatever the caller might've said.
1443 * Furthermore, if the child's parallel awareness matches the Append's,
1444 * then the Append is a no-op and will be discarded later (in setrefs.c).
1445 * Then we can inherit the child's size and cost too, effectively charging
1446 * zero for the Append. Otherwise, we must do the normal costsize
1447 * calculation.
1448 */
1449 if (list_length(pathnode->subpaths) == 1)
1450 {
1451 Path *child = (Path *) linitial(pathnode->subpaths);
1452
1453 if (child->parallel_aware == parallel_aware)
1454 {
1455 pathnode->path.rows = child->rows;
1456 pathnode->path.startup_cost = child->startup_cost;
1457 pathnode->path.total_cost = child->total_cost;
1458 }
1459 else
1461 /* Must do this last, else cost_append complains */
1462 pathnode->path.pathkeys = child->pathkeys;
1463 }
1464 else
1466
1467 /* If the caller provided a row estimate, override the computed value. */
1468 if (rows >= 0)
1469 pathnode->path.rows = rows;
1470
1471 return pathnode;
1472}
void cost_append(AppendPath *apath, PlannerInfo *root)
Definition costsize.c:2311
FILE * input
void list_sort(List *list, list_sort_comparator cmp)
Definition list.c:1674
List * list_concat(List *list1, const List *list2)
Definition list.c:561
static int append_startup_cost_compare(const ListCell *a, const ListCell *b)
Definition pathnode.c:1506
static int append_total_cost_compare(const ListCell *a, const ListCell *b)
Definition pathnode.c:1484
#define linitial(l)
Definition pg_list.h:178
ParamPathInfo * get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
Definition relnode.c:2015
ParamPathInfo * get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
Definition relnode.c:1704
List * pathkeys
Definition pathnodes.h:1999
bool parallel_aware
Definition pathnodes.h:1986

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

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

◆ create_bitmap_and_path()

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

Definition at line 1182 of file pathnode.c.

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

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

Referenced by bitmap_and_cost_est(), and choose_bitmap_and().

◆ create_bitmap_heap_path()

BitmapHeapPath * create_bitmap_heap_path ( PlannerInfo root,
RelOptInfo rel,
Path bitmapqual,
Relids  required_outer,
double  loop_count,
int  parallel_degree 
)
extern

Definition at line 1149 of file pathnode.c.

1155{
1157
1158 pathnode->path.pathtype = T_BitmapHeapScan;
1159 pathnode->path.parent = rel;
1160 pathnode->path.pathtarget = rel->reltarget;
1161 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1163 pathnode->path.parallel_aware = (parallel_degree > 0);
1164 pathnode->path.parallel_safe = rel->consider_parallel;
1165 pathnode->path.parallel_workers = parallel_degree;
1166 pathnode->path.pathkeys = NIL; /* always unordered */
1167
1168 pathnode->bitmapqual = bitmapqual;
1169
1170 cost_bitmap_heap_scan(&pathnode->path, root, rel,
1171 pathnode->path.param_info,
1172 bitmapqual, loop_count);
1173
1174 return pathnode;
1175}
void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, Path *bitmapqual, double loop_count)
Definition costsize.c:1012

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

Referenced by create_index_paths(), create_partial_bitmap_paths(), and reparameterize_path().

◆ create_bitmap_or_path()

BitmapOrPath * create_bitmap_or_path ( PlannerInfo root,
RelOptInfo rel,
List bitmapquals 
)
extern

Definition at line 1234 of file pathnode.c.

1237{
1240 ListCell *lc;
1241
1242 pathnode->path.pathtype = T_BitmapOr;
1243 pathnode->path.parent = rel;
1244 pathnode->path.pathtarget = rel->reltarget;
1245
1246 /*
1247 * Identify the required outer rels as the union of what the child paths
1248 * depend on. (Alternatively, we could insist that the caller pass this
1249 * in, but it's more convenient and reliable to compute it here.)
1250 */
1251 foreach(lc, bitmapquals)
1252 {
1253 Path *bitmapqual = (Path *) lfirst(lc);
1254
1256 PATH_REQ_OUTER(bitmapqual));
1257 }
1258 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1260
1261 /*
1262 * Currently, a BitmapHeapPath, BitmapAndPath, or BitmapOrPath will be
1263 * parallel-safe if and only if rel->consider_parallel is set. So, we can
1264 * set the flag for this path based only on the relation-level flag,
1265 * without actually iterating over the list of children.
1266 */
1267 pathnode->path.parallel_aware = false;
1268 pathnode->path.parallel_safe = rel->consider_parallel;
1269 pathnode->path.parallel_workers = 0;
1270
1271 pathnode->path.pathkeys = NIL; /* always unordered */
1272
1273 pathnode->bitmapquals = bitmapquals;
1274
1275 /* this sets bitmapselectivity as well as the regular cost fields: */
1277
1278 return pathnode;
1279}
void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
Definition costsize.c:1203

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

Referenced by generate_bitmap_or_paths().

◆ create_ctescan_path()

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

Definition at line 2017 of file pathnode.c.

2019{
2021
2022 pathnode->pathtype = T_CteScan;
2023 pathnode->parent = rel;
2024 pathnode->pathtarget = rel->reltarget;
2025 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2027 pathnode->parallel_aware = false;
2028 pathnode->parallel_safe = rel->consider_parallel;
2029 pathnode->parallel_workers = 0;
2030 pathnode->pathkeys = pathkeys;
2031
2032 cost_ctescan(pathnode, root, rel, pathnode->param_info);
2033
2034 return pathnode;
2035}
void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1745

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

Referenced by set_cte_pathlist().

◆ create_foreign_join_path()

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

Definition at line 2176 of file pathnode.c.

2185{
2187
2188 /*
2189 * We should use get_joinrel_parampathinfo to handle parameterized paths,
2190 * but the API of this function doesn't support it, and existing
2191 * extensions aren't yet trying to build such paths anyway. For the
2192 * moment just throw an error if someone tries it; eventually we should
2193 * revisit this.
2194 */
2196 elog(ERROR, "parameterized foreign joins are not supported yet");
2197
2198 pathnode->path.pathtype = T_ForeignScan;
2199 pathnode->path.parent = rel;
2200 pathnode->path.pathtarget = target ? target : rel->reltarget;
2201 pathnode->path.param_info = NULL; /* XXX see above */
2202 pathnode->path.parallel_aware = false;
2203 pathnode->path.parallel_safe = rel->consider_parallel;
2204 pathnode->path.parallel_workers = 0;
2205 pathnode->path.rows = rows;
2206 pathnode->path.disabled_nodes = disabled_nodes;
2207 pathnode->path.startup_cost = startup_cost;
2208 pathnode->path.total_cost = total_cost;
2209 pathnode->path.pathkeys = pathkeys;
2210
2211 pathnode->fdw_outerpath = fdw_outerpath;
2212 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2213 pathnode->fdw_private = fdw_private;
2214
2215 return pathnode;
2216}
#define bms_is_empty(a)
Definition bitmapset.h:118

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

Referenced by add_paths_with_pathkeys_for_rel(), and postgresGetForeignJoinPaths().

◆ create_foreign_upper_path()

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

Definition at line 2230 of file pathnode.c.

2238{
2240
2241 /*
2242 * Upper relations should never have any lateral references, since joining
2243 * is complete.
2244 */
2246
2247 pathnode->path.pathtype = T_ForeignScan;
2248 pathnode->path.parent = rel;
2249 pathnode->path.pathtarget = target ? target : rel->reltarget;
2250 pathnode->path.param_info = NULL;
2251 pathnode->path.parallel_aware = false;
2252 pathnode->path.parallel_safe = rel->consider_parallel;
2253 pathnode->path.parallel_workers = 0;
2254 pathnode->path.rows = rows;
2255 pathnode->path.disabled_nodes = disabled_nodes;
2256 pathnode->path.startup_cost = startup_cost;
2257 pathnode->path.total_cost = total_cost;
2258 pathnode->path.pathkeys = pathkeys;
2259
2260 pathnode->fdw_outerpath = fdw_outerpath;
2261 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2262 pathnode->fdw_private = fdw_private;
2263
2264 return pathnode;
2265}

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

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

◆ create_foreignscan_path()

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

Definition at line 2128 of file pathnode.c.

2137{
2139
2140 /* Historically some FDWs were confused about when to use this */
2141 Assert(IS_SIMPLE_REL(rel));
2142
2143 pathnode->path.pathtype = T_ForeignScan;
2144 pathnode->path.parent = rel;
2145 pathnode->path.pathtarget = target ? target : rel->reltarget;
2146 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
2148 pathnode->path.parallel_aware = false;
2149 pathnode->path.parallel_safe = rel->consider_parallel;
2150 pathnode->path.parallel_workers = 0;
2151 pathnode->path.rows = rows;
2152 pathnode->path.disabled_nodes = disabled_nodes;
2153 pathnode->path.startup_cost = startup_cost;
2154 pathnode->path.total_cost = total_cost;
2155 pathnode->path.pathkeys = pathkeys;
2156
2157 pathnode->fdw_outerpath = fdw_outerpath;
2158 pathnode->fdw_restrictinfo = fdw_restrictinfo;
2159 pathnode->fdw_private = fdw_private;
2160
2161 return pathnode;
2162}
#define IS_SIMPLE_REL(rel)
Definition pathnodes.h:977

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

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

◆ create_functionscan_path()

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

Definition at line 1939 of file pathnode.c.

1941{
1943
1944 pathnode->pathtype = T_FunctionScan;
1945 pathnode->parent = rel;
1946 pathnode->pathtarget = rel->reltarget;
1947 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1949 pathnode->parallel_aware = false;
1950 pathnode->parallel_safe = rel->consider_parallel;
1951 pathnode->parallel_workers = 0;
1952 pathnode->pathkeys = pathkeys;
1953
1954 cost_functionscan(pathnode, root, rel, pathnode->param_info);
1955
1956 return pathnode;
1957}
void cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1563

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

Referenced by set_function_pathlist().

◆ create_gather_merge_path()

GatherMergePath * create_gather_merge_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target,
List pathkeys,
Relids  required_outer,
double rows 
)
extern

Definition at line 1813 of file pathnode.c.

1816{
1818 int input_disabled_nodes = 0;
1821
1822 Assert(subpath->parallel_safe);
1823 Assert(pathkeys);
1824
1825 /*
1826 * The subpath should guarantee that it is adequately ordered either by
1827 * adding an explicit sort node or by using presorted input. We cannot
1828 * add an explicit Sort node for the subpath in createplan.c on additional
1829 * pathkeys, because we can't guarantee the sort would be safe. For
1830 * example, expressions may be volatile or otherwise parallel unsafe.
1831 */
1832 if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
1833 elog(ERROR, "gather merge input not sufficiently sorted");
1834
1835 pathnode->path.pathtype = T_GatherMerge;
1836 pathnode->path.parent = rel;
1837 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1839 pathnode->path.parallel_aware = false;
1840
1841 pathnode->subpath = subpath;
1842 pathnode->num_workers = subpath->parallel_workers;
1843 pathnode->path.pathkeys = pathkeys;
1844 pathnode->path.pathtarget = target ? target : rel->reltarget;
1845
1846 input_disabled_nodes += subpath->disabled_nodes;
1847 input_startup_cost += subpath->startup_cost;
1848 input_total_cost += subpath->total_cost;
1849
1850 cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
1852 input_total_cost, rows);
1853
1854 return pathnode;
1855}
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:470
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition pathkeys.c:343

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

Referenced by create_ordered_paths(), gather_grouping_paths(), generate_gather_paths(), and generate_useful_gather_paths().

◆ create_gather_path()

GatherPath * create_gather_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target,
Relids  required_outer,
double rows 
)
extern

Definition at line 1865 of file pathnode.c.

1867{
1869
1870 Assert(subpath->parallel_safe);
1871
1872 pathnode->path.pathtype = T_Gather;
1873 pathnode->path.parent = rel;
1874 pathnode->path.pathtarget = target;
1875 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1877 pathnode->path.parallel_aware = false;
1878 pathnode->path.parallel_safe = false;
1879 pathnode->path.parallel_workers = 0;
1880 pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1881
1882 pathnode->subpath = subpath;
1883 pathnode->num_workers = subpath->parallel_workers;
1884 pathnode->single_copy = false;
1885
1886 if (pathnode->num_workers == 0)
1887 {
1888 pathnode->path.pathkeys = subpath->pathkeys;
1889 pathnode->num_workers = 1;
1890 pathnode->single_copy = true;
1891 }
1892
1893 cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1894
1895 return pathnode;
1896}
void cost_gather(GatherPath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, double *rows)
Definition costsize.c:430

References Assert, cost_gather(), fb(), get_baserel_parampathinfo(), makeNode, NIL, root, and subpath().

Referenced by generate_gather_paths(), and generate_union_paths().

◆ create_group_path()

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

Definition at line 2948 of file pathnode.c.

2954{
2956 PathTarget *target = rel->reltarget;
2957
2958 pathnode->path.pathtype = T_Group;
2959 pathnode->path.parent = rel;
2960 pathnode->path.pathtarget = target;
2961 /* For now, assume we are above any joins, so no parameterization */
2962 pathnode->path.param_info = NULL;
2963 pathnode->path.parallel_aware = false;
2964 pathnode->path.parallel_safe = rel->consider_parallel &&
2965 subpath->parallel_safe;
2966 pathnode->path.parallel_workers = subpath->parallel_workers;
2967 /* Group doesn't change sort ordering */
2968 pathnode->path.pathkeys = subpath->pathkeys;
2969
2970 pathnode->subpath = subpath;
2971
2972 pathnode->groupClause = groupClause;
2973 pathnode->qual = qual;
2974
2975 cost_group(&pathnode->path, root,
2976 list_length(groupClause),
2977 numGroups,
2978 qual,
2979 subpath->disabled_nodes,
2980 subpath->startup_cost, subpath->total_cost,
2981 subpath->rows);
2982
2983 /* add tlist eval cost for each output row */
2984 pathnode->path.startup_cost += target->cost.startup;
2985 pathnode->path.total_cost += target->cost.startup +
2986 target->cost.per_tuple * pathnode->path.rows;
2987
2988 return pathnode;
2989}
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:3301

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

Referenced by add_paths_to_grouping_rel(), and create_partial_grouping_paths().

◆ create_group_result_path()

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

Definition at line 1664 of file pathnode.c.

1666{
1668
1669 pathnode->path.pathtype = T_Result;
1670 pathnode->path.parent = rel;
1671 pathnode->path.pathtarget = target;
1672 pathnode->path.param_info = NULL; /* there are no other rels... */
1673 pathnode->path.parallel_aware = false;
1674 pathnode->path.parallel_safe = rel->consider_parallel;
1675 pathnode->path.parallel_workers = 0;
1676 pathnode->path.pathkeys = NIL;
1677 pathnode->quals = havingqual;
1678
1679 /*
1680 * We can't quite use cost_resultscan() because the quals we want to
1681 * account for are not baserestrict quals of the rel. Might as well just
1682 * hack it here.
1683 */
1684 pathnode->path.rows = 1;
1685 pathnode->path.startup_cost = target->cost.startup;
1686 pathnode->path.total_cost = target->cost.startup +
1687 cpu_tuple_cost + target->cost.per_tuple;
1688
1689 /*
1690 * Add cost of qual, if any --- but we ignore its selectivity, since our
1691 * rowcount estimate should be 1 no matter what the qual is.
1692 */
1693 if (havingqual)
1694 {
1696
1698 /* havingqual is evaluated once at startup */
1699 pathnode->path.startup_cost += qual_cost.startup + qual_cost.per_tuple;
1700 pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
1701 }
1702
1703 return pathnode;
1704}
double cpu_tuple_cost
Definition costsize.c:133
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition costsize.c:4899

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

Referenced by create_degenerate_grouping_paths(), and query_planner().

◆ create_groupingsets_path()

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

Definition at line 3139 of file pathnode.c.

3146{
3148 PathTarget *target = rel->reltarget;
3149 ListCell *lc;
3150 bool is_first = true;
3151 bool is_first_sort = true;
3152
3153 /* The topmost generated Plan node will be an Agg */
3154 pathnode->path.pathtype = T_Agg;
3155 pathnode->path.parent = rel;
3156 pathnode->path.pathtarget = target;
3157 pathnode->path.param_info = subpath->param_info;
3158 pathnode->path.parallel_aware = false;
3159 pathnode->path.parallel_safe = rel->consider_parallel &&
3160 subpath->parallel_safe;
3161 pathnode->path.parallel_workers = subpath->parallel_workers;
3162 pathnode->subpath = subpath;
3163
3164 /*
3165 * Simplify callers by downgrading AGG_SORTED to AGG_PLAIN, and AGG_MIXED
3166 * to AGG_HASHED, here if possible.
3167 */
3168 if (aggstrategy == AGG_SORTED &&
3169 list_length(rollups) == 1 &&
3170 ((RollupData *) linitial(rollups))->groupClause == NIL)
3171 aggstrategy = AGG_PLAIN;
3172
3173 if (aggstrategy == AGG_MIXED &&
3174 list_length(rollups) == 1)
3175 aggstrategy = AGG_HASHED;
3176
3177 /*
3178 * Output will be in sorted order by group_pathkeys if, and only if, there
3179 * is a single rollup operation on a non-empty list of grouping
3180 * expressions.
3181 */
3182 if (aggstrategy == AGG_SORTED && list_length(rollups) == 1)
3183 pathnode->path.pathkeys = root->group_pathkeys;
3184 else
3185 pathnode->path.pathkeys = NIL;
3186
3187 pathnode->aggstrategy = aggstrategy;
3188 pathnode->rollups = rollups;
3189 pathnode->qual = having_qual;
3190 pathnode->transitionSpace = agg_costs ? agg_costs->transitionSpace : 0;
3191
3192 Assert(rollups != NIL);
3193 Assert(aggstrategy != AGG_PLAIN || list_length(rollups) == 1);
3194 Assert(aggstrategy != AGG_MIXED || list_length(rollups) > 1);
3195
3196 foreach(lc, rollups)
3197 {
3199 List *gsets = rollup->gsets;
3200 int numGroupCols = list_length(linitial(gsets));
3201
3202 /*
3203 * In AGG_SORTED or AGG_PLAIN mode, the first rollup takes the
3204 * (already-sorted) input, and following ones do their own sort.
3205 *
3206 * In AGG_HASHED mode, there is one rollup for each grouping set.
3207 *
3208 * In AGG_MIXED mode, the first rollups are hashed, the first
3209 * non-hashed one takes the (already-sorted) input, and following ones
3210 * do their own sort.
3211 */
3212 if (is_first)
3213 {
3214 cost_agg(&pathnode->path, root,
3215 aggstrategy,
3216 agg_costs,
3218 rollup->numGroups,
3220 subpath->disabled_nodes,
3221 subpath->startup_cost,
3222 subpath->total_cost,
3223 subpath->rows,
3224 subpath->pathtarget->width);
3225 is_first = false;
3226 if (!rollup->is_hashed)
3227 is_first_sort = false;
3228 }
3229 else
3230 {
3231 Path sort_path; /* dummy for result of cost_sort */
3232 Path agg_path; /* dummy for result of cost_agg */
3233
3234 if (rollup->is_hashed || is_first_sort)
3235 {
3236 /*
3237 * Account for cost of aggregation, but don't charge input
3238 * cost again
3239 */
3241 rollup->is_hashed ? AGG_HASHED : AGG_SORTED,
3242 agg_costs,
3244 rollup->numGroups,
3246 0, 0.0, 0.0,
3247 subpath->rows,
3248 subpath->pathtarget->width);
3249 if (!rollup->is_hashed)
3250 is_first_sort = false;
3251 }
3252 else
3253 {
3254 /* Account for cost of sort, but don't charge input cost again */
3256 0.0,
3257 subpath->rows,
3258 subpath->pathtarget->width,
3259 0.0,
3260 work_mem,
3261 -1.0);
3262
3263 /* Account for cost of aggregation */
3264
3266 AGG_SORTED,
3267 agg_costs,
3269 rollup->numGroups,
3271 sort_path.disabled_nodes,
3272 sort_path.startup_cost,
3273 sort_path.total_cost,
3274 sort_path.rows,
3275 subpath->pathtarget->width);
3276 }
3277
3278 pathnode->path.disabled_nodes += agg_path.disabled_nodes;
3279 pathnode->path.total_cost += agg_path.total_cost;
3280 pathnode->path.rows += agg_path.rows;
3281 }
3282 }
3283
3284 /* add tlist eval cost for each output row */
3285 pathnode->path.startup_cost += target->cost.startup;
3286 pathnode->path.total_cost += target->cost.startup +
3287 target->cost.per_tuple * pathnode->path.rows;
3288
3289 return pathnode;
3290}
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:2201
int work_mem
Definition globals.c:131
@ AGG_HASHED
Definition nodes.h:366
@ AGG_MIXED
Definition nodes.h:367
@ AGG_PLAIN
Definition nodes.h:364

References AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, Assert, RelOptInfo::consider_parallel, PathTarget::cost, cost_agg(), cost_sort(), fb(), lfirst, linitial, list_length(), makeNode, NIL, QualCost::per_tuple, RelOptInfo::reltarget, root, QualCost::startup, subpath(), and work_mem.

Referenced by consider_groupingsets_paths().

◆ create_hashjoin_path()

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

Definition at line 2521 of file pathnode.c.

2532{
2534
2535 pathnode->jpath.path.pathtype = T_HashJoin;
2536 pathnode->jpath.path.parent = joinrel;
2537 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2538 pathnode->jpath.path.param_info =
2540 joinrel,
2541 outer_path,
2542 inner_path,
2543 extra->sjinfo,
2546 pathnode->jpath.path.parallel_aware =
2547 joinrel->consider_parallel && parallel_hash;
2548 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2549 outer_path->parallel_safe && inner_path->parallel_safe;
2550 /* This is a foolish way to estimate parallel_workers, but for now... */
2551 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2552
2553 /*
2554 * A hashjoin never has pathkeys, since its output ordering is
2555 * unpredictable due to possible batching. XXX If the inner relation is
2556 * small enough, we could instruct the executor that it must not batch,
2557 * and then we could assume that the output inherits the outer relation's
2558 * ordering, which might save a sort step. However there is considerable
2559 * downside if our estimate of the inner relation size is badly off. For
2560 * the moment we don't risk it. (Note also that if we wanted to take this
2561 * seriously, joinpath.c would have to consider many more paths for the
2562 * outer rel than it does now.)
2563 */
2564 pathnode->jpath.path.pathkeys = NIL;
2565 pathnode->jpath.jointype = jointype;
2566 pathnode->jpath.inner_unique = extra->inner_unique;
2567 pathnode->jpath.outerjoinpath = outer_path;
2568 pathnode->jpath.innerjoinpath = inner_path;
2569 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2570 pathnode->path_hashclauses = hashclauses;
2571 /* final_cost_hashjoin will fill in pathnode->num_batches */
2572
2573 final_cost_hashjoin(root, pathnode, workspace, extra);
2574
2575 return pathnode;
2576}
void final_cost_hashjoin(PlannerInfo *root, HashPath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition costsize.c:4416
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:1818
SpecialJoinInfo * sjinfo
Definition pathnodes.h:3596

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

Referenced by try_hashjoin_path(), and try_partial_hashjoin_path().

◆ create_incremental_sort_path()

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

Definition at line 2855 of file pathnode.c.

2861{
2863 SortPath *pathnode = &sort->spath;
2864
2866 pathnode->path.parent = rel;
2867 /* Sort doesn't project, so use source path's pathtarget */
2868 pathnode->path.pathtarget = subpath->pathtarget;
2869 pathnode->path.param_info = subpath->param_info;
2870 pathnode->path.parallel_aware = false;
2871 pathnode->path.parallel_safe = rel->consider_parallel &&
2872 subpath->parallel_safe;
2873 pathnode->path.parallel_workers = subpath->parallel_workers;
2874 pathnode->path.pathkeys = pathkeys;
2875
2876 pathnode->subpath = subpath;
2877
2879 root, pathkeys, presorted_keys,
2880 subpath->disabled_nodes,
2881 subpath->startup_cost,
2882 subpath->total_cost,
2883 subpath->rows,
2884 subpath->pathtarget->width,
2885 0.0, /* XXX comparison_cost shouldn't be 0? */
2886 work_mem, limit_tuples);
2887
2888 sort->nPresortedCols = presorted_keys;
2889
2890 return sort;
2891}
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:2053
NodeTag pathtype
Definition pathnodes.h:1959
Path path
Definition pathnodes.h:2525

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

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

◆ create_index_path()

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

Definition at line 1092 of file pathnode.c.

1103{
1105 RelOptInfo *rel = index->rel;
1106
1107 pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
1108 pathnode->path.parent = rel;
1109 pathnode->path.pathtarget = rel->reltarget;
1110 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1112 pathnode->path.parallel_aware = false;
1113 pathnode->path.parallel_safe = rel->consider_parallel;
1114 pathnode->path.parallel_workers = 0;
1115 pathnode->path.pathkeys = pathkeys;
1116
1117 pathnode->indexinfo = index;
1118 pathnode->indexclauses = indexclauses;
1119 pathnode->indexorderbys = indexorderbys;
1120 pathnode->indexorderbycols = indexorderbycols;
1121 pathnode->indexscandir = indexscandir;
1122
1124
1125 /*
1126 * cost_index will set disabled_nodes to 1 if this rel is not allowed to
1127 * use index scans in general, but it doesn't have the IndexOptInfo to
1128 * know whether this specific index has been disabled.
1129 */
1130 if (index->disabled)
1131 pathnode->path.disabled_nodes = 1;
1132
1133 return pathnode;
1134}
void cost_index(IndexPath *path, PlannerInfo *root, double loop_count, bool partial_path)
Definition costsize.c:545
Definition type.h:96

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

Referenced by build_index_paths(), and plan_cluster_use_sort().

◆ create_limit_path()

LimitPath * create_limit_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
Node limitOffset,
Node limitCount,
LimitOption  limitOption,
int64  offset_est,
int64  count_est 
)
extern

Definition at line 3792 of file pathnode.c.

3797{
3799
3800 pathnode->path.pathtype = T_Limit;
3801 pathnode->path.parent = rel;
3802 /* Limit doesn't project, so use source path's pathtarget */
3803 pathnode->path.pathtarget = subpath->pathtarget;
3804 /* For now, assume we are above any joins, so no parameterization */
3805 pathnode->path.param_info = NULL;
3806 pathnode->path.parallel_aware = false;
3807 pathnode->path.parallel_safe = rel->consider_parallel &&
3808 subpath->parallel_safe;
3809 pathnode->path.parallel_workers = subpath->parallel_workers;
3810 pathnode->path.rows = subpath->rows;
3811 pathnode->path.disabled_nodes = subpath->disabled_nodes;
3812 pathnode->path.startup_cost = subpath->startup_cost;
3813 pathnode->path.total_cost = subpath->total_cost;
3814 pathnode->path.pathkeys = subpath->pathkeys;
3815 pathnode->subpath = subpath;
3816 pathnode->limitOffset = limitOffset;
3817 pathnode->limitCount = limitCount;
3818 pathnode->limitOption = limitOption;
3819
3820 /*
3821 * Adjust the output rows count and costs according to the offset/limit.
3822 */
3824 &pathnode->path.startup_cost,
3825 &pathnode->path.total_cost,
3826 offset_est, count_est);
3827
3828 return pathnode;
3829}
void adjust_limit_rows_costs(double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
Definition pathnode.c:3848

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

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

◆ create_lockrows_path()

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

Definition at line 3630 of file pathnode.c.

3632{
3634
3635 pathnode->path.pathtype = T_LockRows;
3636 pathnode->path.parent = rel;
3637 /* LockRows doesn't project, so use source path's pathtarget */
3638 pathnode->path.pathtarget = subpath->pathtarget;
3639 /* For now, assume we are above any joins, so no parameterization */
3640 pathnode->path.param_info = NULL;
3641 pathnode->path.parallel_aware = false;
3642 pathnode->path.parallel_safe = false;
3643 pathnode->path.parallel_workers = 0;
3644 pathnode->path.rows = subpath->rows;
3645
3646 /*
3647 * The result cannot be assumed sorted, since locking might cause the sort
3648 * key columns to be replaced with new values.
3649 */
3650 pathnode->path.pathkeys = NIL;
3651
3652 pathnode->subpath = subpath;
3653 pathnode->rowMarks = rowMarks;
3654 pathnode->epqParam = epqParam;
3655
3656 /*
3657 * We should charge something extra for the costs of row locking and
3658 * possible refetches, but it's hard to say how much. For now, use
3659 * cpu_tuple_cost per row.
3660 */
3661 pathnode->path.disabled_nodes = subpath->disabled_nodes;
3662 pathnode->path.startup_cost = subpath->startup_cost;
3663 pathnode->path.total_cost = subpath->total_cost +
3664 cpu_tuple_cost * subpath->rows;
3665
3666 return pathnode;
3667}

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

Referenced by grouping_planner().

◆ create_material_path()

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

Definition at line 1712 of file pathnode.c.

1713{
1715
1716 Assert(subpath->parent == rel);
1717
1718 pathnode->path.pathtype = T_Material;
1719 pathnode->path.parent = rel;
1720 pathnode->path.pathtarget = rel->reltarget;
1721 pathnode->path.param_info = subpath->param_info;
1722 pathnode->path.parallel_aware = false;
1723 pathnode->path.parallel_safe = rel->consider_parallel &&
1724 subpath->parallel_safe;
1725 pathnode->path.parallel_workers = subpath->parallel_workers;
1726 pathnode->path.pathkeys = subpath->pathkeys;
1727
1728 pathnode->subpath = subpath;
1729
1730 cost_material(&pathnode->path,
1731 enabled,
1732 subpath->disabled_nodes,
1733 subpath->startup_cost,
1734 subpath->total_cost,
1735 subpath->rows,
1736 subpath->pathtarget->width);
1737
1738 return pathnode;
1739}
void cost_material(Path *path, bool enabled, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition costsize.c:2583

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

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

◆ create_memoize_path()

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

Definition at line 1746 of file pathnode.c.

1749{
1751
1752 Assert(subpath->parent == rel);
1753
1754 pathnode->path.pathtype = T_Memoize;
1755 pathnode->path.parent = rel;
1756 pathnode->path.pathtarget = rel->reltarget;
1757 pathnode->path.param_info = subpath->param_info;
1758 pathnode->path.parallel_aware = false;
1759 pathnode->path.parallel_safe = rel->consider_parallel &&
1760 subpath->parallel_safe;
1761 pathnode->path.parallel_workers = subpath->parallel_workers;
1762 pathnode->path.pathkeys = subpath->pathkeys;
1763
1764 pathnode->subpath = subpath;
1765 pathnode->hash_operators = hash_operators;
1766 pathnode->param_exprs = param_exprs;
1767 pathnode->singlerow = singlerow;
1768 pathnode->binary_mode = binary_mode;
1769
1770 /*
1771 * For now we set est_entries to 0. cost_memoize_rescan() does all the
1772 * hard work to determine how many cache entries there are likely to be,
1773 * so it seems best to leave it up to that function to fill this field in.
1774 * If left at 0, the executor will make a guess at a good value.
1775 */
1776 pathnode->est_entries = 0;
1777
1778 pathnode->est_calls = clamp_row_est(est_calls);
1779
1780 /* These will also be set later in cost_memoize_rescan() */
1781 pathnode->est_unique_keys = 0.0;
1782 pathnode->est_hit_ratio = 0.0;
1783
1784 /*
1785 * We should not be asked to generate this path type when memoization is
1786 * disabled, so set our count of disabled nodes equal to the subpath's
1787 * count.
1788 *
1789 * It would be nice to also Assert that memoization is enabled, but the
1790 * value of enable_memoize is not controlling: what we would need to check
1791 * is that the JoinPathExtraData's pgs_mask included PGS_NESTLOOP_MEMOIZE.
1792 */
1793 pathnode->path.disabled_nodes = subpath->disabled_nodes;
1794
1795 /*
1796 * Add a small additional charge for caching the first entry. All the
1797 * harder calculations for rescans are performed in cost_memoize_rescan().
1798 */
1799 pathnode->path.startup_cost = subpath->startup_cost + cpu_tuple_cost;
1800 pathnode->path.total_cost = subpath->total_cost + cpu_tuple_cost;
1801 pathnode->path.rows = subpath->rows;
1802
1803 return pathnode;
1804}

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

Referenced by get_memoize_path(), and reparameterize_path().

◆ create_merge_append_path()

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

Definition at line 1524 of file pathnode.c.

1530{
1535 ListCell *l;
1536
1537 /*
1538 * We don't currently support parameterized MergeAppend paths, as
1539 * explained in the comments for generate_orderedappend_paths.
1540 */
1542
1543 pathnode->child_append_relid_sets = child_append_relid_sets;
1544 pathnode->path.pathtype = T_MergeAppend;
1545 pathnode->path.parent = rel;
1546 pathnode->path.pathtarget = rel->reltarget;
1547 pathnode->path.param_info = NULL;
1548 pathnode->path.parallel_aware = false;
1549 pathnode->path.parallel_safe = rel->consider_parallel;
1550 pathnode->path.parallel_workers = 0;
1551 pathnode->path.pathkeys = pathkeys;
1552 pathnode->subpaths = subpaths;
1553
1554 /*
1555 * Apply query-wide LIMIT if known and path is for sole base relation.
1556 * (Handling this at this low level is a bit klugy.)
1557 */
1558 if (bms_equal(rel->relids, root->all_query_rels))
1559 pathnode->limit_tuples = root->limit_tuples;
1560 else
1561 pathnode->limit_tuples = -1.0;
1562
1563 /*
1564 * Add up the sizes and costs of the input paths.
1565 */
1566 pathnode->path.rows = 0;
1569 input_total_cost = 0;
1570 foreach(l, subpaths)
1571 {
1572 Path *subpath = (Path *) lfirst(l);
1573 int presorted_keys;
1574 Path sort_path; /* dummy for result of
1575 * cost_sort/cost_incremental_sort */
1576
1577 /* All child paths should be unparameterized */
1579
1580 pathnode->path.rows += subpath->rows;
1581 pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
1582 subpath->parallel_safe;
1583
1584 if (!pathkeys_count_contained_in(pathkeys, subpath->pathkeys,
1585 &presorted_keys))
1586 {
1587 /*
1588 * We'll need to insert a Sort node, so include costs for that. We
1589 * choose to use incremental sort if it is enabled and there are
1590 * presorted keys; otherwise we use full sort.
1591 *
1592 * We can use the parent's LIMIT if any, since we certainly won't
1593 * pull more than that many tuples from any child.
1594 */
1595 if (enable_incremental_sort && presorted_keys > 0)
1596 {
1598 root,
1599 pathkeys,
1600 presorted_keys,
1601 subpath->disabled_nodes,
1602 subpath->startup_cost,
1603 subpath->total_cost,
1604 subpath->rows,
1605 subpath->pathtarget->width,
1606 0.0,
1607 work_mem,
1608 pathnode->limit_tuples);
1609 }
1610 else
1611 {
1613 root,
1614 pathkeys,
1615 subpath->disabled_nodes,
1616 subpath->total_cost,
1617 subpath->rows,
1618 subpath->pathtarget->width,
1619 0.0,
1620 work_mem,
1621 pathnode->limit_tuples);
1622 }
1623
1624 subpath = &sort_path;
1625 }
1626
1627 input_disabled_nodes += subpath->disabled_nodes;
1628 input_startup_cost += subpath->startup_cost;
1629 input_total_cost += subpath->total_cost;
1630 }
1631
1632 /*
1633 * Now we can compute total costs of the MergeAppend. If there's exactly
1634 * one child path and its parallel awareness matches that of the
1635 * MergeAppend, then the MergeAppend is a no-op and will be discarded
1636 * later (in setrefs.c); otherwise we do the normal cost calculation.
1637 */
1638 if (list_length(subpaths) == 1 &&
1639 ((Path *) linitial(subpaths))->parallel_aware ==
1640 pathnode->path.parallel_aware)
1641 {
1642 pathnode->path.disabled_nodes = input_disabled_nodes;
1643 pathnode->path.startup_cost = input_startup_cost;
1644 pathnode->path.total_cost = input_total_cost;
1645 }
1646 else
1648 pathkeys, list_length(subpaths),
1651 pathnode->path.rows);
1652
1653 return pathnode;
1654}
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:2525
bool enable_incremental_sort
Definition costsize.c:152
bool pathkeys_count_contained_in(List *keys1, List *keys2, int *n_common)
Definition pathkeys.c:558

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

Referenced by generate_orderedappend_paths(), and generate_union_paths().

◆ create_mergejoin_path()

MergePath * create_mergejoin_path ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
JoinCostWorkspace workspace,
JoinPathExtraData extra,
Path outer_path,
Path inner_path,
List restrict_clauses,
List pathkeys,
Relids  required_outer,
List mergeclauses,
List outersortkeys,
List innersortkeys,
int  outer_presorted_keys 
)
extern

Definition at line 2453 of file pathnode.c.

2467{
2469
2470 pathnode->jpath.path.pathtype = T_MergeJoin;
2471 pathnode->jpath.path.parent = joinrel;
2472 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2473 pathnode->jpath.path.param_info =
2475 joinrel,
2476 outer_path,
2477 inner_path,
2478 extra->sjinfo,
2481 pathnode->jpath.path.parallel_aware = false;
2482 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2483 outer_path->parallel_safe && inner_path->parallel_safe;
2484 /* This is a foolish way to estimate parallel_workers, but for now... */
2485 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2486 pathnode->jpath.path.pathkeys = pathkeys;
2487 pathnode->jpath.jointype = jointype;
2488 pathnode->jpath.inner_unique = extra->inner_unique;
2489 pathnode->jpath.outerjoinpath = outer_path;
2490 pathnode->jpath.innerjoinpath = inner_path;
2491 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2492 pathnode->path_mergeclauses = mergeclauses;
2493 pathnode->outersortkeys = outersortkeys;
2494 pathnode->innersortkeys = innersortkeys;
2495 pathnode->outer_presorted_keys = outer_presorted_keys;
2496 /* pathnode->skip_mark_restore will be set by final_cost_mergejoin */
2497 /* pathnode->materialize_inner will be set by final_cost_mergejoin */
2498
2499 final_cost_mergejoin(root, pathnode, workspace, extra);
2500
2501 return pathnode;
2502}
void final_cost_mergejoin(PlannerInfo *root, MergePath *path, JoinCostWorkspace *workspace, JoinPathExtraData *extra)
Definition costsize.c:3955

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

Referenced by try_mergejoin_path(), and try_partial_mergejoin_path().

◆ create_minmaxagg_path()

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

Definition at line 3302 of file pathnode.c.

3307{
3311 ListCell *lc;
3312
3313 /* The topmost generated Plan node will be a Result */
3314 pathnode->path.pathtype = T_Result;
3315 pathnode->path.parent = rel;
3316 pathnode->path.pathtarget = target;
3317 /* For now, assume we are above any joins, so no parameterization */
3318 pathnode->path.param_info = NULL;
3319 pathnode->path.parallel_aware = false;
3320 pathnode->path.parallel_safe = true; /* might change below */
3321 pathnode->path.parallel_workers = 0;
3322 /* Result is one unordered row */
3323 pathnode->path.rows = 1;
3324 pathnode->path.pathkeys = NIL;
3325
3326 pathnode->mmaggregates = mmaggregates;
3327 pathnode->quals = quals;
3328
3329 /* Calculate cost of all the initplans, and check parallel safety */
3330 initplan_cost = 0;
3331 foreach(lc, mmaggregates)
3332 {
3334
3336 initplan_cost += mminfo->pathcost;
3337 if (!mminfo->path->parallel_safe)
3338 pathnode->path.parallel_safe = false;
3339 }
3340
3341 /* add tlist eval cost for each output row, plus cpu_tuple_cost */
3342 pathnode->path.disabled_nodes = initplan_disabled_nodes;
3343 pathnode->path.startup_cost = initplan_cost + target->cost.startup;
3344 pathnode->path.total_cost = initplan_cost + target->cost.startup +
3345 target->cost.per_tuple + cpu_tuple_cost;
3346
3347 /*
3348 * Add cost of qual, if any --- but we ignore its selectivity, since our
3349 * rowcount estimate should be 1 no matter what the qual is.
3350 */
3351 if (quals)
3352 {
3354
3355 cost_qual_eval(&qual_cost, quals, root);
3356 pathnode->path.startup_cost += qual_cost.startup;
3357 pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
3358 }
3359
3360 /*
3361 * If the initplans were all parallel-safe, also check safety of the
3362 * target and quals. (The Result node itself isn't parallelizable, but if
3363 * we are in a subquery then it can be useful for the outer query to know
3364 * that this one is parallel-safe.)
3365 */
3366 if (pathnode->path.parallel_safe)
3367 pathnode->path.parallel_safe =
3368 is_parallel_safe(root, (Node *) target->exprs) &&
3369 is_parallel_safe(root, (Node *) quals);
3370
3371 return pathnode;
3372}
int disabled_nodes
Definition pathnodes.h:1994

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

Referenced by preprocess_minmax_aggregates().

◆ create_modifytable_path()

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

Definition at line 3692 of file pathnode.c.

3702{
3704
3705 Assert(operation == CMD_MERGE ||
3706 (operation == CMD_UPDATE ?
3707 list_length(resultRelations) == list_length(updateColnosLists) :
3708 updateColnosLists == NIL));
3709 Assert(withCheckOptionLists == NIL ||
3710 list_length(resultRelations) == list_length(withCheckOptionLists));
3711 Assert(returningLists == NIL ||
3712 list_length(resultRelations) == list_length(returningLists));
3713
3714 pathnode->path.pathtype = T_ModifyTable;
3715 pathnode->path.parent = rel;
3716 /* pathtarget is not interesting, just make it minimally valid */
3717 pathnode->path.pathtarget = rel->reltarget;
3718 /* For now, assume we are above any joins, so no parameterization */
3719 pathnode->path.param_info = NULL;
3720 pathnode->path.parallel_aware = false;
3721 pathnode->path.parallel_safe = false;
3722 pathnode->path.parallel_workers = 0;
3723 pathnode->path.pathkeys = NIL;
3724
3725 /*
3726 * Compute cost & rowcount as subpath cost & rowcount (if RETURNING)
3727 *
3728 * Currently, we don't charge anything extra for the actual table
3729 * modification work, nor for the WITH CHECK OPTIONS or RETURNING
3730 * expressions if any. It would only be window dressing, since
3731 * ModifyTable is always a top-level node and there is no way for the
3732 * costs to change any higher-level planning choices. But we might want
3733 * to make it look better sometime.
3734 */
3735 pathnode->path.disabled_nodes = subpath->disabled_nodes;
3736 pathnode->path.startup_cost = subpath->startup_cost;
3737 pathnode->path.total_cost = subpath->total_cost;
3738 if (returningLists != NIL)
3739 {
3740 pathnode->path.rows = subpath->rows;
3741
3742 /*
3743 * Set width to match the subpath output. XXX this is totally wrong:
3744 * we should return an average of the RETURNING tlist widths. But
3745 * it's what happened historically, and improving it is a task for
3746 * another day. (Again, it's mostly window dressing.)
3747 */
3748 pathnode->path.pathtarget->width = subpath->pathtarget->width;
3749 }
3750 else
3751 {
3752 pathnode->path.rows = 0;
3753 pathnode->path.pathtarget->width = 0;
3754 }
3755
3756 pathnode->subpath = subpath;
3757 pathnode->operation = operation;
3758 pathnode->canSetTag = canSetTag;
3759 pathnode->nominalRelation = nominalRelation;
3760 pathnode->rootRelation = rootRelation;
3761 pathnode->resultRelations = resultRelations;
3762 pathnode->updateColnosLists = updateColnosLists;
3763 pathnode->withCheckOptionLists = withCheckOptionLists;
3764 pathnode->returningLists = returningLists;
3765 pathnode->rowMarks = rowMarks;
3766 pathnode->onconflict = onconflict;
3767 pathnode->epqParam = epqParam;
3768 pathnode->mergeActionLists = mergeActionLists;
3769 pathnode->mergeJoinConditions = mergeJoinConditions;
3770
3771 return pathnode;
3772}
@ CMD_MERGE
Definition nodes.h:279
@ CMD_UPDATE
Definition nodes.h:276

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

Referenced by grouping_planner().

◆ create_namedtuplestorescan_path()

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

Definition at line 2043 of file pathnode.c.

2045{
2047
2048 pathnode->pathtype = T_NamedTuplestoreScan;
2049 pathnode->parent = rel;
2050 pathnode->pathtarget = rel->reltarget;
2051 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2053 pathnode->parallel_aware = false;
2054 pathnode->parallel_safe = rel->consider_parallel;
2055 pathnode->parallel_workers = 0;
2056 pathnode->pathkeys = NIL; /* result is always unordered */
2057
2058 cost_namedtuplestorescan(pathnode, root, rel, pathnode->param_info);
2059
2060 return pathnode;
2061}
void cost_namedtuplestorescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1791

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

Referenced by set_namedtuplestore_pathlist().

◆ create_nestloop_path()

NestPath * create_nestloop_path ( PlannerInfo root,
RelOptInfo joinrel,
JoinType  jointype,
JoinCostWorkspace workspace,
JoinPathExtraData extra,
Path outer_path,
Path inner_path,
List restrict_clauses,
List pathkeys,
Relids  required_outer 
)
extern

Definition at line 2356 of file pathnode.c.

2366{
2369 Relids outerrelids;
2370
2371 /*
2372 * Paths are parameterized by top-level parents, so run parameterization
2373 * tests on the parent relids.
2374 */
2375 if (outer_path->parent->top_parent_relids)
2376 outerrelids = outer_path->parent->top_parent_relids;
2377 else
2378 outerrelids = outer_path->parent->relids;
2379
2380 /*
2381 * If the inner path is parameterized by the outer, we must drop any
2382 * restrict_clauses that are due to be moved into the inner path. We have
2383 * to do this now, rather than postpone the work till createplan time,
2384 * because the restrict_clauses list can affect the size and cost
2385 * estimates for this path. We detect such clauses by checking for serial
2386 * number match to clauses already enforced in the inner path.
2387 */
2388 if (bms_overlap(inner_req_outer, outerrelids))
2389 {
2391 List *jclauses = NIL;
2392 ListCell *lc;
2393
2394 foreach(lc, restrict_clauses)
2395 {
2396 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2397
2399 jclauses = lappend(jclauses, rinfo);
2400 }
2402 }
2403
2404 pathnode->jpath.path.pathtype = T_NestLoop;
2405 pathnode->jpath.path.parent = joinrel;
2406 pathnode->jpath.path.pathtarget = joinrel->reltarget;
2407 pathnode->jpath.path.param_info =
2409 joinrel,
2410 outer_path,
2411 inner_path,
2412 extra->sjinfo,
2415 pathnode->jpath.path.parallel_aware = false;
2416 pathnode->jpath.path.parallel_safe = joinrel->consider_parallel &&
2417 outer_path->parallel_safe && inner_path->parallel_safe;
2418 /* This is a foolish way to estimate parallel_workers, but for now... */
2419 pathnode->jpath.path.parallel_workers = outer_path->parallel_workers;
2420 pathnode->jpath.path.pathkeys = pathkeys;
2421 pathnode->jpath.jointype = jointype;
2422 pathnode->jpath.inner_unique = extra->inner_unique;
2423 pathnode->jpath.outerjoinpath = outer_path;
2424 pathnode->jpath.innerjoinpath = inner_path;
2425 pathnode->jpath.joinrestrictinfo = restrict_clauses;
2426
2427 final_cost_nestloop(root, pathnode, workspace, extra);
2428
2429 return pathnode;
2430}
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:3455
Bitmapset * get_param_path_clause_serials(Path *path)
Definition relnode.c:2069

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

Referenced by try_nestloop_path(), and try_partial_nestloop_path().

◆ create_projection_path()

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

Definition at line 2587 of file pathnode.c.

2591{
2594
2595 /*
2596 * We mustn't put a ProjectionPath directly above another; it's useless
2597 * and will confuse create_projection_plan. Rather than making sure all
2598 * callers handle that, let's implement it here, by stripping off any
2599 * ProjectionPath in what we're given. Given this rule, there won't be
2600 * more than one.
2601 */
2603 {
2605
2606 Assert(subpp->path.parent == rel);
2607 subpath = subpp->subpath;
2609 }
2610
2611 pathnode->path.pathtype = T_Result;
2612 pathnode->path.parent = rel;
2613 pathnode->path.pathtarget = target;
2614 pathnode->path.param_info = subpath->param_info;
2615 pathnode->path.parallel_aware = false;
2616 pathnode->path.parallel_safe = rel->consider_parallel &&
2617 subpath->parallel_safe &&
2618 is_parallel_safe(root, (Node *) target->exprs);
2619 pathnode->path.parallel_workers = subpath->parallel_workers;
2620 /* Projection does not change the sort order */
2621 pathnode->path.pathkeys = subpath->pathkeys;
2622
2623 pathnode->subpath = subpath;
2624
2625 /*
2626 * We might not need a separate Result node. If the input plan node type
2627 * can project, we can just tell it to project something else. Or, if it
2628 * can't project but the desired target has the same expression list as
2629 * what the input will produce anyway, we can still give it the desired
2630 * tlist (possibly changing its ressortgroupref labels, but nothing else).
2631 * Note: in the latter case, create_projection_plan has to recheck our
2632 * conclusion; see comments therein.
2633 */
2634 oldtarget = subpath->pathtarget;
2636 equal(oldtarget->exprs, target->exprs))
2637 {
2638 /* No separate Result node needed */
2639 pathnode->dummypp = true;
2640
2641 /*
2642 * Set cost of plan as subpath's cost, adjusted for tlist replacement.
2643 */
2644 pathnode->path.rows = subpath->rows;
2645 pathnode->path.disabled_nodes = subpath->disabled_nodes;
2646 pathnode->path.startup_cost = subpath->startup_cost +
2647 (target->cost.startup - oldtarget->cost.startup);
2648 pathnode->path.total_cost = subpath->total_cost +
2649 (target->cost.startup - oldtarget->cost.startup) +
2650 (target->cost.per_tuple - oldtarget->cost.per_tuple) * subpath->rows;
2651 }
2652 else
2653 {
2654 /* We really do need the Result node */
2655 pathnode->dummypp = false;
2656
2657 /*
2658 * The Result node's cost is cpu_tuple_cost per row, plus the cost of
2659 * evaluating the tlist. There is no qual to worry about.
2660 */
2661 pathnode->path.rows = subpath->rows;
2662 pathnode->path.disabled_nodes = subpath->disabled_nodes;
2663 pathnode->path.startup_cost = subpath->startup_cost +
2664 target->cost.startup;
2665 pathnode->path.total_cost = subpath->total_cost +
2666 target->cost.startup +
2667 (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows;
2668 }
2669
2670 return pathnode;
2671}
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223

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

Referenced by add_paths_with_pathkeys_for_rel(), adjust_paths_for_srfs(), apply_projection_to_path(), apply_scanjoin_target_to_paths(), create_final_unique_paths(), create_partial_grouping_paths(), create_partial_unique_paths(), generate_grouped_paths(), and recurse_set_operations().

◆ create_recursiveunion_path()

RecursiveUnionPath * create_recursiveunion_path ( PlannerInfo root,
RelOptInfo rel,
Path leftpath,
Path rightpath,
PathTarget target,
List distinctList,
int  wtParam,
double  numGroups 
)
extern

Definition at line 3585 of file pathnode.c.

3593{
3595
3596 pathnode->path.pathtype = T_RecursiveUnion;
3597 pathnode->path.parent = rel;
3598 pathnode->path.pathtarget = target;
3599 /* For now, assume we are above any joins, so no parameterization */
3600 pathnode->path.param_info = NULL;
3601 pathnode->path.parallel_aware = false;
3602 pathnode->path.parallel_safe = rel->consider_parallel &&
3603 leftpath->parallel_safe && rightpath->parallel_safe;
3604 /* Foolish, but we'll do it like joins for now: */
3605 pathnode->path.parallel_workers = leftpath->parallel_workers;
3606 /* RecursiveUnion result is always unsorted */
3607 pathnode->path.pathkeys = NIL;
3608
3609 pathnode->leftpath = leftpath;
3610 pathnode->rightpath = rightpath;
3611 pathnode->distinctList = distinctList;
3612 pathnode->wtParam = wtParam;
3613 pathnode->numGroups = numGroups;
3614
3615 cost_recursive_union(&pathnode->path, leftpath, rightpath);
3616
3617 return pathnode;
3618}
void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
Definition costsize.c:1875
int parallel_workers
Definition pathnodes.h:1990

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

Referenced by generate_recursion_path().

◆ create_rel_agg_info()

RelAggInfo * create_rel_agg_info ( PlannerInfo root,
RelOptInfo rel,
bool  calculate_grouped_rows 
)
extern

Definition at line 2691 of file relnode.c.

2693{
2694 ListCell *lc;
2695 RelAggInfo *result;
2696 PathTarget *agg_input;
2697 PathTarget *target;
2698 List *group_clauses = NIL;
2699 List *group_exprs = NIL;
2700
2701 /*
2702 * The lists of aggregate expressions and grouping expressions should have
2703 * been constructed.
2704 */
2705 Assert(root->agg_clause_list != NIL);
2706 Assert(root->group_expr_list != NIL);
2707
2708 /*
2709 * If this is a child rel, the grouped rel for its parent rel must have
2710 * been created if it can. So we can just use parent's RelAggInfo if
2711 * there is one, with appropriate variable substitutions.
2712 */
2713 if (IS_OTHER_REL(rel))
2714 {
2715 RelOptInfo *grouped_rel;
2716 RelAggInfo *agg_info;
2717
2718 grouped_rel = rel->top_parent->grouped_rel;
2719 if (grouped_rel == NULL)
2720 return NULL;
2721
2722 Assert(IS_GROUPED_REL(grouped_rel));
2723
2724 /* Must do multi-level transformation */
2725 agg_info = (RelAggInfo *)
2727 (Node *) grouped_rel->agg_info,
2728 rel,
2729 rel->top_parent);
2730
2731 agg_info->apply_agg_at = NULL; /* caller will change this later */
2732
2734 {
2735 agg_info->grouped_rows =
2737 rel->rows, NULL, NULL);
2738
2739 /*
2740 * The grouped paths for the given relation are considered useful
2741 * iff the average group size is no less than
2742 * min_eager_agg_group_size.
2743 */
2744 agg_info->agg_useful =
2745 (rel->rows / agg_info->grouped_rows) >= min_eager_agg_group_size;
2746 }
2747
2748 return agg_info;
2749 }
2750
2751 /* Check if it's possible to produce grouped paths for this relation. */
2753 return NULL;
2754
2755 /*
2756 * Create targets for the grouped paths and for the input paths of the
2757 * grouped paths.
2758 */
2759 target = create_empty_pathtarget();
2760 agg_input = create_empty_pathtarget();
2761
2762 /* ... and initialize these targets */
2763 if (!init_grouping_targets(root, rel, target, agg_input,
2764 &group_clauses, &group_exprs))
2765 return NULL;
2766
2767 /*
2768 * Eager aggregation is not applicable if there are no available grouping
2769 * expressions.
2770 */
2771 if (group_clauses == NIL)
2772 return NULL;
2773
2774 /* Add aggregates to the grouping target */
2775 foreach(lc, root->agg_clause_list)
2776 {
2778 Aggref *aggref;
2779
2780 Assert(IsA(ac_info->aggref, Aggref));
2781
2782 aggref = (Aggref *) copyObject(ac_info->aggref);
2784
2785 add_column_to_pathtarget(target, (Expr *) aggref, 0);
2786 }
2787
2788 /* Set the estimated eval cost and output width for both targets */
2790 set_pathtarget_cost_width(root, agg_input);
2791
2792 /* build the RelAggInfo result */
2793 result = makeNode(RelAggInfo);
2794 result->target = target;
2795 result->agg_input = agg_input;
2796 result->group_clauses = group_clauses;
2797 result->group_exprs = group_exprs;
2798 result->apply_agg_at = NULL; /* caller will change this later */
2799
2801 {
2803 rel->rows, NULL, NULL);
2804
2805 /*
2806 * The grouped paths for the given relation are considered useful iff
2807 * the average group size is no less than min_eager_agg_group_size.
2808 */
2809 result->agg_useful =
2810 (rel->rows / result->grouped_rows) >= min_eager_agg_group_size;
2811 }
2812
2813 return result;
2814}
double min_eager_agg_group_size
Definition allpaths.c:84
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition appendinfo.c:597
PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
Definition costsize.c:6510
#define copyObject(obj)
Definition nodes.h:232
@ AGGSPLIT_INITIAL_SERIAL
Definition nodes.h:389
#define IS_GROUPED_REL(rel)
Definition pathnodes.h:1245
#define lfirst_node(type, lc)
Definition pg_list.h:176
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition planner.c:5818
static bool init_grouping_targets(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, PathTarget *agg_input, List **group_clauses, List **group_exprs)
Definition relnode.c:2901
static bool eager_aggregation_possible_for_relation(PlannerInfo *root, RelOptInfo *rel)
Definition relnode.c:2821
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition selfuncs.c:3788
List * group_exprs
Definition pathnodes.h:1287
List * group_clauses
Definition pathnodes.h:1285
struct PathTarget * agg_input
Definition pathnodes.h:1282
void add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
Definition tlist.c:704

References add_column_to_pathtarget(), adjust_appendrel_attrs_multilevel(), RelOptInfo::agg_info, RelAggInfo::agg_input, RelAggInfo::agg_useful, AGGSPLIT_INITIAL_SERIAL, RelAggInfo::apply_agg_at, Assert, copyObject, create_empty_pathtarget(), eager_aggregation_possible_for_relation(), estimate_num_groups(), fb(), RelAggInfo::group_clauses, RelAggInfo::group_exprs, RelOptInfo::grouped_rel, RelAggInfo::grouped_rows, init_grouping_targets(), IS_GROUPED_REL, IS_OTHER_REL, IsA, lfirst_node, makeNode, mark_partial_aggref(), min_eager_agg_group_size, NIL, root, RelOptInfo::rows, set_pathtarget_cost_width(), and RelAggInfo::target.

Referenced by build_simple_grouped_rel(), and make_grouped_join_rel().

◆ create_resultscan_path()

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

Definition at line 2069 of file pathnode.c.

2071{
2073
2074 pathnode->pathtype = T_Result;
2075 pathnode->parent = rel;
2076 pathnode->pathtarget = rel->reltarget;
2077 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2079 pathnode->parallel_aware = false;
2080 pathnode->parallel_safe = rel->consider_parallel;
2081 pathnode->parallel_workers = 0;
2082 pathnode->pathkeys = NIL; /* result is always unordered */
2083
2084 cost_resultscan(pathnode, root, rel, pathnode->param_info);
2085
2086 return pathnode;
2087}
void cost_resultscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1833

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

Referenced by reparameterize_path(), and set_result_pathlist().

◆ create_samplescan_path()

Path * create_samplescan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer 
)
extern

Definition at line 1051 of file pathnode.c.

1052{
1054
1055 pathnode->pathtype = T_SampleScan;
1056 pathnode->parent = rel;
1057 pathnode->pathtarget = rel->reltarget;
1058 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1060 pathnode->parallel_aware = false;
1061 pathnode->parallel_safe = rel->consider_parallel;
1062 pathnode->parallel_workers = 0;
1063 pathnode->pathkeys = NIL; /* samplescan has unordered result */
1064
1065 cost_samplescan(pathnode, root, rel, pathnode->param_info);
1066
1067 return pathnode;
1068}
void cost_samplescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:349

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

Referenced by reparameterize_path(), and set_tablesample_rel_pathlist().

◆ create_seqscan_path()

Path * create_seqscan_path ( PlannerInfo root,
RelOptInfo rel,
Relids  required_outer,
int  parallel_workers 
)
extern

Definition at line 1026 of file pathnode.c.

1028{
1030
1031 pathnode->pathtype = T_SeqScan;
1032 pathnode->parent = rel;
1033 pathnode->pathtarget = rel->reltarget;
1034 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1036 pathnode->parallel_aware = (parallel_workers > 0);
1037 pathnode->parallel_safe = rel->consider_parallel;
1038 pathnode->parallel_workers = parallel_workers;
1039 pathnode->pathkeys = NIL; /* seqscan has unordered result */
1040
1041 cost_seqscan(pathnode, root, rel, pathnode->param_info);
1042
1043 return pathnode;
1044}
void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:270

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

Referenced by create_plain_partial_paths(), plan_cluster_use_sort(), reparameterize_path(), and set_plain_rel_pathlist().

◆ create_set_projection_path()

ProjectSetPath * create_set_projection_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
PathTarget target 
)
extern

Definition at line 2785 of file pathnode.c.

2789{
2791 double tlist_rows;
2792 ListCell *lc;
2793
2794 pathnode->path.pathtype = T_ProjectSet;
2795 pathnode->path.parent = rel;
2796 pathnode->path.pathtarget = target;
2797 /* For now, assume we are above any joins, so no parameterization */
2798 pathnode->path.param_info = NULL;
2799 pathnode->path.parallel_aware = false;
2800 pathnode->path.parallel_safe = rel->consider_parallel &&
2801 subpath->parallel_safe &&
2802 is_parallel_safe(root, (Node *) target->exprs);
2803 pathnode->path.parallel_workers = subpath->parallel_workers;
2804 /* Projection does not change the sort order XXX? */
2805 pathnode->path.pathkeys = subpath->pathkeys;
2806
2807 pathnode->subpath = subpath;
2808
2809 /*
2810 * Estimate number of rows produced by SRFs for each row of input; if
2811 * there's more than one in this node, use the maximum.
2812 */
2813 tlist_rows = 1;
2814 foreach(lc, target->exprs)
2815 {
2816 Node *node = (Node *) lfirst(lc);
2817 double itemrows;
2818
2820 if (tlist_rows < itemrows)
2822 }
2823
2824 /*
2825 * In addition to the cost of evaluating the tlist, charge cpu_tuple_cost
2826 * per input row, and half of cpu_tuple_cost for each added output row.
2827 * This is slightly bizarre maybe, but it's what 9.6 did; we may revisit
2828 * this estimate later.
2829 */
2830 pathnode->path.disabled_nodes = subpath->disabled_nodes;
2831 pathnode->path.rows = subpath->rows * tlist_rows;
2832 pathnode->path.startup_cost = subpath->startup_cost +
2833 target->cost.startup;
2834 pathnode->path.total_cost = subpath->total_cost +
2835 target->cost.startup +
2836 (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows +
2837 (pathnode->path.rows - subpath->rows) * cpu_tuple_cost / 2;
2838
2839 return pathnode;
2840}
double expression_returns_set_rows(PlannerInfo *root, Node *clause)
Definition clauses.c:300

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

Referenced by adjust_paths_for_srfs().

◆ create_setop_path()

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

Definition at line 3466 of file pathnode.c.

3475{
3477
3478 pathnode->path.pathtype = T_SetOp;
3479 pathnode->path.parent = rel;
3480 pathnode->path.pathtarget = rel->reltarget;
3481 /* For now, assume we are above any joins, so no parameterization */
3482 pathnode->path.param_info = NULL;
3483 pathnode->path.parallel_aware = false;
3484 pathnode->path.parallel_safe = rel->consider_parallel &&
3485 leftpath->parallel_safe && rightpath->parallel_safe;
3486 pathnode->path.parallel_workers =
3487 leftpath->parallel_workers + rightpath->parallel_workers;
3488 /* SetOp preserves the input sort order if in sort mode */
3489 pathnode->path.pathkeys =
3490 (strategy == SETOP_SORTED) ? leftpath->pathkeys : NIL;
3491
3492 pathnode->leftpath = leftpath;
3493 pathnode->rightpath = rightpath;
3494 pathnode->cmd = cmd;
3495 pathnode->strategy = strategy;
3496 pathnode->groupList = groupList;
3497 pathnode->numGroups = numGroups;
3498
3499 /*
3500 * Compute cost estimates. As things stand, we end up with the same total
3501 * cost in this node for sort and hash methods, but different startup
3502 * costs. This could be refined perhaps, but it'll do for now.
3503 */
3504 pathnode->path.disabled_nodes =
3505 leftpath->disabled_nodes + rightpath->disabled_nodes;
3506 if (strategy == SETOP_SORTED)
3507 {
3508 /*
3509 * In sorted mode, we can emit output incrementally. Charge one
3510 * cpu_operator_cost per comparison per input tuple. Like cost_group,
3511 * we assume all columns get compared at most of the tuples.
3512 */
3513 pathnode->path.startup_cost =
3514 leftpath->startup_cost + rightpath->startup_cost;
3515 pathnode->path.total_cost =
3516 leftpath->total_cost + rightpath->total_cost +
3517 cpu_operator_cost * (leftpath->rows + rightpath->rows) * list_length(groupList);
3518
3519 /*
3520 * Also charge a small amount per extracted tuple. Like cost_sort,
3521 * charge only operator cost not cpu_tuple_cost, since SetOp does no
3522 * qual-checking or projection.
3523 */
3524 pathnode->path.total_cost += cpu_operator_cost * outputRows;
3525 }
3526 else
3527 {
3529
3530 /*
3531 * In hashed mode, we must read all the input before we can emit
3532 * anything. Also charge comparison costs to represent the cost of
3533 * hash table lookups.
3534 */
3535 pathnode->path.startup_cost =
3536 leftpath->total_cost + rightpath->total_cost +
3537 cpu_operator_cost * (leftpath->rows + rightpath->rows) * list_length(groupList);
3538 pathnode->path.total_cost = pathnode->path.startup_cost;
3539
3540 /*
3541 * Also charge a small amount per extracted tuple. Like cost_sort,
3542 * charge only operator cost not cpu_tuple_cost, since SetOp does no
3543 * qual-checking or projection.
3544 */
3545 pathnode->path.total_cost += cpu_operator_cost * outputRows;
3546
3547 /*
3548 * Mark the path as disabled if enable_hashagg is off. While this
3549 * isn't exactly a HashAgg node, it seems close enough to justify
3550 * letting that switch control it.
3551 */
3552 if (!enable_hashagg)
3553 pathnode->path.disabled_nodes++;
3554
3555 /*
3556 * Also disable if it doesn't look like the hashtable will fit into
3557 * hash_mem. (Note: reject on equality, to ensure that an estimate of
3558 * SIZE_MAX disables hashing regardless of the hash_mem limit.)
3559 */
3561 leftpath->pathtarget->width);
3563 pathnode->path.disabled_nodes++;
3564 }
3565 pathnode->path.rows = outputRows;
3566
3567 return pathnode;
3568}
size_t Size
Definition c.h:691
double cpu_operator_cost
Definition costsize.c:135
bool enable_hashagg
Definition costsize.c:153
size_t get_hash_memory_limit(void)
Definition nodeHash.c:3680
Size EstimateSetOpHashTableSpace(double nentries, Size tupleWidth)
Definition nodeSetOp.c:116
@ SETOP_SORTED
Definition nodes.h:416

References RelOptInfo::consider_parallel, cpu_operator_cost, Path::disabled_nodes, enable_hashagg, EstimateSetOpHashTableSpace(), fb(), get_hash_memory_limit(), list_length(), makeNode, NIL, Path::parallel_safe, Path::parallel_workers, Path::pathkeys, RelOptInfo::reltarget, Path::rows, SETOP_SORTED, Path::startup_cost, and Path::total_cost.

Referenced by generate_nonunion_paths().

◆ create_sort_path()

SortPath * create_sort_path ( PlannerInfo root,
RelOptInfo rel,
Path subpath,
List pathkeys,
double  limit_tuples 
)
extern

Definition at line 2904 of file pathnode.c.

2909{
2911
2912 pathnode->path.pathtype = T_Sort;
2913 pathnode->path.parent = rel;
2914 /* Sort doesn't project, so use source path's pathtarget */
2915 pathnode->path.pathtarget = subpath->pathtarget;
2916 pathnode->path.param_info = subpath->param_info;
2917 pathnode->path.parallel_aware = false;
2918 pathnode->path.parallel_safe = rel->consider_parallel &&
2919 subpath->parallel_safe;
2920 pathnode->path.parallel_workers = subpath->parallel_workers;
2921 pathnode->path.pathkeys = pathkeys;
2922
2923 pathnode->subpath = subpath;
2924
2925 cost_sort(&pathnode->path, root, pathkeys,
2926 subpath->disabled_nodes,
2927 subpath->total_cost,
2928 subpath->rows,
2929 subpath->pathtarget->width,
2930 0.0, /* XXX comparison_cost shouldn't be 0? */
2931 work_mem, limit_tuples);
2932
2933 return pathnode;
2934}

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

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

◆ create_subqueryscan_path()

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

Definition at line 1909 of file pathnode.c.

1912{
1914
1915 pathnode->path.pathtype = T_SubqueryScan;
1916 pathnode->path.parent = rel;
1917 pathnode->path.pathtarget = rel->reltarget;
1918 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1920 pathnode->path.parallel_aware = false;
1921 pathnode->path.parallel_safe = rel->consider_parallel &&
1922 subpath->parallel_safe;
1923 pathnode->path.parallel_workers = subpath->parallel_workers;
1924 pathnode->path.pathkeys = pathkeys;
1925 pathnode->subpath = subpath;
1926
1927 cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
1929
1930 return pathnode;
1931}
void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, bool trivial_pathtarget)
Definition costsize.c:1478

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

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

◆ create_tablefuncscan_path()

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

Definition at line 1965 of file pathnode.c.

1967{
1969
1970 pathnode->pathtype = T_TableFuncScan;
1971 pathnode->parent = rel;
1972 pathnode->pathtarget = rel->reltarget;
1973 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1975 pathnode->parallel_aware = false;
1976 pathnode->parallel_safe = rel->consider_parallel;
1977 pathnode->parallel_workers = 0;
1978 pathnode->pathkeys = NIL; /* result is always unordered */
1979
1980 cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
1981
1982 return pathnode;
1983}
void cost_tablefuncscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1629

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

Referenced by set_tablefunc_pathlist().

◆ create_tidrangescan_path()

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

Definition at line 1315 of file pathnode.c.

1318{
1320
1321 pathnode->path.pathtype = T_TidRangeScan;
1322 pathnode->path.parent = rel;
1323 pathnode->path.pathtarget = rel->reltarget;
1324 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1326 pathnode->path.parallel_aware = (parallel_workers > 0);
1327 pathnode->path.parallel_safe = rel->consider_parallel;
1328 pathnode->path.parallel_workers = parallel_workers;
1329 pathnode->path.pathkeys = NIL; /* always unordered */
1330
1331 pathnode->tidrangequals = tidrangequals;
1332
1333 cost_tidrangescan(&pathnode->path, root, rel, tidrangequals,
1334 pathnode->path.param_info);
1335
1336 return pathnode;
1337}
void cost_tidrangescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, List *tidrangequals, ParamPathInfo *param_info)
Definition costsize.c:1361

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

Referenced by create_tidscan_paths().

◆ create_tidscan_path()

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

Definition at line 1286 of file pathnode.c.

1288{
1290
1291 pathnode->path.pathtype = T_TidScan;
1292 pathnode->path.parent = rel;
1293 pathnode->path.pathtarget = rel->reltarget;
1294 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1296 pathnode->path.parallel_aware = false;
1297 pathnode->path.parallel_safe = rel->consider_parallel;
1298 pathnode->path.parallel_workers = 0;
1299 pathnode->path.pathkeys = NIL; /* always unordered */
1300
1301 pathnode->tidquals = tidquals;
1302
1303 cost_tidscan(&pathnode->path, root, rel, tidquals,
1304 pathnode->path.param_info);
1305
1306 return pathnode;
1307}
void cost_tidscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info)
Definition costsize.c:1251

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

Referenced by BuildParameterizedTidPaths(), and create_tidscan_paths().

◆ create_unique_path()

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

Definition at line 3005 of file pathnode.c.

3010{
3012
3013 pathnode->path.pathtype = T_Unique;
3014 pathnode->path.parent = rel;
3015 /* Unique doesn't project, so use source path's pathtarget */
3016 pathnode->path.pathtarget = subpath->pathtarget;
3017 pathnode->path.param_info = subpath->param_info;
3018 pathnode->path.parallel_aware = false;
3019 pathnode->path.parallel_safe = rel->consider_parallel &&
3020 subpath->parallel_safe;
3021 pathnode->path.parallel_workers = subpath->parallel_workers;
3022 /* Unique doesn't change the input ordering */
3023 pathnode->path.pathkeys = subpath->pathkeys;
3024
3025 pathnode->subpath = subpath;
3026 pathnode->numkeys = numCols;
3027
3028 /*
3029 * Charge one cpu_operator_cost per comparison per input tuple. We assume
3030 * all columns get compared at most of the tuples. (XXX probably this is
3031 * an overestimate.)
3032 */
3033 pathnode->path.disabled_nodes = subpath->disabled_nodes;
3034 pathnode->path.startup_cost = subpath->startup_cost;
3035 pathnode->path.total_cost = subpath->total_cost +
3036 cpu_operator_cost * subpath->rows * numCols;
3037 pathnode->path.rows = numGroups;
3038
3039 return pathnode;
3040}

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

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

◆ create_valuesscan_path()

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

Definition at line 1991 of file pathnode.c.

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

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

Referenced by set_values_pathlist().

◆ create_windowagg_path()

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

Definition at line 3393 of file pathnode.c.

3402{
3404
3405 /* qual can only be set for the topwindow */
3406 Assert(qual == NIL || topwindow);
3407
3408 pathnode->path.pathtype = T_WindowAgg;
3409 pathnode->path.parent = rel;
3410 pathnode->path.pathtarget = target;
3411 /* For now, assume we are above any joins, so no parameterization */
3412 pathnode->path.param_info = NULL;
3413 pathnode->path.parallel_aware = false;
3414 pathnode->path.parallel_safe = rel->consider_parallel &&
3415 subpath->parallel_safe;
3416 pathnode->path.parallel_workers = subpath->parallel_workers;
3417 /* WindowAgg preserves the input sort order */
3418 pathnode->path.pathkeys = subpath->pathkeys;
3419
3420 pathnode->subpath = subpath;
3421 pathnode->winclause = winclause;
3422 pathnode->qual = qual;
3423 pathnode->runCondition = runCondition;
3424 pathnode->topwindow = topwindow;
3425
3426 /*
3427 * For costing purposes, assume that there are no redundant partitioning
3428 * or ordering columns; it's not worth the trouble to deal with that
3429 * corner case here. So we just pass the unmodified list lengths to
3430 * cost_windowagg.
3431 */
3433 windowFuncs,
3434 winclause,
3435 subpath->disabled_nodes,
3436 subpath->startup_cost,
3437 subpath->total_cost,
3438 subpath->rows);
3439
3440 /* add tlist eval cost for each output row */
3441 pathnode->path.startup_cost += target->cost.startup;
3442 pathnode->path.total_cost += target->cost.startup +
3443 target->cost.per_tuple * pathnode->path.rows;
3444
3445 return pathnode;
3446}
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:3204

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

Referenced by create_one_window_path().

◆ create_worktablescan_path()

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

Definition at line 2095 of file pathnode.c.

2097{
2099
2100 pathnode->pathtype = T_WorkTableScan;
2101 pathnode->parent = rel;
2102 pathnode->pathtarget = rel->reltarget;
2103 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2105 pathnode->parallel_aware = false;
2106 pathnode->parallel_safe = rel->consider_parallel;
2107 pathnode->parallel_workers = 0;
2108 pathnode->pathkeys = NIL; /* result is always unordered */
2109
2110 /* Cost is the same as for a regular CTE scan */
2111 cost_ctescan(pathnode, root, rel, pathnode->param_info);
2112
2113 return pathnode;
2114}

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

Referenced by set_worktable_pathlist().

◆ expand_planner_arrays()

void expand_planner_arrays ( PlannerInfo root,
int  add_size 
)
extern

Definition at line 183 of file relnode.c.

184{
185 int new_size;
186
187 Assert(add_size > 0);
188
189 new_size = root->simple_rel_array_size + add_size;
190
191 root->simple_rel_array =
192 repalloc0_array(root->simple_rel_array, RelOptInfo *, root->simple_rel_array_size, new_size);
193
194 root->simple_rte_array =
195 repalloc0_array(root->simple_rte_array, RangeTblEntry *, root->simple_rel_array_size, new_size);
196
197 if (root->append_rel_array)
198 root->append_rel_array =
199 repalloc0_array(root->append_rel_array, AppendRelInfo *, root->simple_rel_array_size, new_size);
200 else
201 root->append_rel_array =
203
204 root->simple_rel_array_size = new_size;
205}
#define repalloc0_array(pointer, type, oldcount, count)
Definition palloc.h:109
Size add_size(Size s1, Size s2)
Definition shmem.c:485

References add_size(), Assert, fb(), palloc0_array, repalloc0_array, and root.

Referenced by expand_inherited_rtentry(), and expand_partitioned_rtentry().

◆ fetch_upper_rel()

RelOptInfo * fetch_upper_rel ( PlannerInfo root,
UpperRelationKind  kind,
Relids  relids 
)
extern

Definition at line 1617 of file relnode.c.

1618{
1620 ListCell *lc;
1621
1622 /*
1623 * For the moment, our indexing data structure is just a List for each
1624 * relation kind. If we ever get so many of one kind that this stops
1625 * working well, we can improve it. No code outside this function should
1626 * assume anything about how to find a particular upperrel.
1627 */
1628
1629 /* If we already made this upperrel for the query, return it */
1630 foreach(lc, root->upper_rels[kind])
1631 {
1633
1634 if (bms_equal(upperrel->relids, relids))
1635 return upperrel;
1636 }
1637
1639 upperrel->reloptkind = RELOPT_UPPER_REL;
1640 upperrel->relids = bms_copy(relids);
1641 upperrel->pgs_mask = root->glob->default_pgs_mask;
1642
1643 /* cheap startup cost is interesting iff not all tuples to be retrieved */
1644 upperrel->consider_startup = (root->tuple_fraction > 0);
1645 upperrel->consider_param_startup = false;
1646 upperrel->consider_parallel = false; /* might get changed later */
1647 upperrel->reltarget = create_empty_pathtarget();
1648 upperrel->pathlist = NIL;
1649 upperrel->cheapest_startup_path = NULL;
1650 upperrel->cheapest_total_path = NULL;
1651 upperrel->cheapest_parameterized_paths = NIL;
1652
1653 root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
1654
1655 return upperrel;
1656}
@ RELOPT_UPPER_REL
Definition pathnodes.h:969

References bms_copy(), bms_equal(), create_empty_pathtarget(), fb(), lappend(), lfirst, makeNode, NIL, RELOPT_UPPER_REL, and root.

Referenced by add_rtes_to_flat_rtable(), build_setop_child_paths(), create_distinct_paths(), create_ordered_paths(), create_partial_distinct_paths(), create_partial_grouping_paths(), create_window_paths(), generate_nonunion_paths(), generate_recursion_path(), generate_union_paths(), grouping_planner(), make_grouping_rel(), make_subplan(), preprocess_minmax_aggregates(), set_subquery_pathlist(), set_subquery_size_estimates(), SS_process_ctes(), standard_planner(), and subquery_planner().

◆ find_base_rel()

◆ find_base_rel_ignore_join()

RelOptInfo * find_base_rel_ignore_join ( PlannerInfo root,
int  relid 
)
extern

Definition at line 584 of file relnode.c.

585{
586 /* use an unsigned comparison to prevent negative array element access */
587 if ((uint32) relid < (uint32) root->simple_rel_array_size)
588 {
589 RelOptInfo *rel;
591
592 rel = root->simple_rel_array[relid];
593 if (rel)
594 return rel;
595
596 /*
597 * We could just return NULL here, but for debugging purposes it seems
598 * best to actually verify that the relid is an outer join and not
599 * something weird.
600 */
601 rte = root->simple_rte_array[relid];
602 if (rte && rte->rtekind == RTE_JOIN && rte->jointype != JOIN_INNER)
603 return NULL;
604 }
605
606 elog(ERROR, "no relation entry for relid %d", relid);
607
608 return NULL; /* keep compiler quiet */
609}

References elog, ERROR, fb(), JOIN_INNER, root, and RTE_JOIN.

Referenced by add_join_clause_to_rels(), create_lateral_join_info(), eager_aggregation_possible_for_relation(), find_appinfos_by_relids(), and remove_join_clause_from_rels().

◆ find_base_rel_noerr()

RelOptInfo * find_base_rel_noerr ( PlannerInfo root,
int  relid 
)
extern

Definition at line 566 of file relnode.c.

567{
568 /* use an unsigned comparison to prevent negative array element access */
569 if ((uint32) relid < (uint32) root->simple_rel_array_size)
570 return root->simple_rel_array[relid];
571 return NULL;
572}

References fb(), and root.

Referenced by all_rows_selectable().

◆ find_childrel_parents()

Relids find_childrel_parents ( PlannerInfo root,
RelOptInfo rel 
)
extern

Definition at line 1668 of file relnode.c.

1669{
1670 Relids result = NULL;
1671
1673 Assert(rel->relid > 0 && rel->relid < root->simple_rel_array_size);
1674
1675 do
1676 {
1677 AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
1679
1680 result = bms_add_member(result, prelid);
1681
1682 /* traverse up to the parent rel, loop if it's also a child rel */
1683 rel = find_base_rel(root, prelid);
1684 } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
1685
1687
1688 return result;
1689}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
unsigned int Index
Definition c.h:700
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition relnode.c:544
Index parent_relid
Definition pathnodes.h:3288

References Assert, bms_add_member(), fb(), find_base_rel(), AppendRelInfo::parent_relid, RelOptInfo::relid, RELOPT_BASEREL, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, and root.

Referenced by check_index_predicates(), and generate_implied_equalities_for_column().

◆ find_join_rel()

RelOptInfo * find_join_rel ( PlannerInfo root,
Relids  relids 
)
extern

Definition at line 657 of file relnode.c.

658{
659 /*
660 * Switch to using hash lookup when list grows "too long". The threshold
661 * is arbitrary and is known only here.
662 */
663 if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
665
666 /*
667 * Use either hashtable lookup or linear search, as appropriate.
668 *
669 * Note: the seemingly redundant hashkey variable is used to avoid taking
670 * the address of relids; unless the compiler is exceedingly smart, doing
671 * so would force relids out of a register and thus probably slow down the
672 * list-search case.
673 */
674 if (root->join_rel_hash)
675 {
676 Relids hashkey = relids;
678
679 hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
680 &hashkey,
681 HASH_FIND,
682 NULL);
683 if (hentry)
684 return hentry->join_rel;
685 }
686 else
687 {
688 ListCell *l;
689
690 foreach(l, root->join_rel_list)
691 {
692 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
693
694 if (bms_equal(rel->relids, relids))
695 return rel;
696 }
697 }
698
699 return NULL;
700}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
@ HASH_FIND
Definition hsearch.h:113
static void build_join_rel_hash(PlannerInfo *root)
Definition relnode.c:616
RelOptInfo * join_rel
Definition relnode.c:47

References bms_equal(), build_join_rel_hash(), fb(), HASH_FIND, hash_search(), JoinHashEntry::join_rel, lfirst, list_length(), RelOptInfo::relids, and root.

Referenced by build_child_join_rel(), build_join_rel(), examine_variable(), find_join_input_rel(), get_matching_part_pairs(), and postgresPlanDirectModify().

◆ find_param_path_info()

ParamPathInfo * find_param_path_info ( RelOptInfo rel,
Relids  required_outer 
)
extern

Definition at line 2048 of file relnode.c.

2049{
2050 ListCell *lc;
2051
2052 foreach(lc, rel->ppilist)
2053 {
2055
2056 if (bms_equal(ppi->ppi_req_outer, required_outer))
2057 return ppi;
2058 }
2059
2060 return NULL;
2061}

References bms_equal(), fb(), lfirst, and RelOptInfo::ppilist.

Referenced by get_appendrel_parampathinfo(), get_baserel_parampathinfo(), get_joinrel_parampathinfo(), and reparameterize_path_by_child().

◆ get_appendrel_parampathinfo()

ParamPathInfo * get_appendrel_parampathinfo ( RelOptInfo appendrel,
Relids  required_outer 
)
extern

Definition at line 2015 of file relnode.c.

2016{
2018
2019 /* If rel has LATERAL refs, every path for it should account for them */
2020 Assert(bms_is_subset(appendrel->lateral_relids, required_outer));
2021
2022 /* Unparameterized paths have no ParamPathInfo */
2024 return NULL;
2025
2027
2028 /* If we already have a PPI for this parameterization, just return it */
2030 return ppi;
2031
2032 /* Else build the ParamPathInfo */
2034 ppi->ppi_req_outer = required_outer;
2035 ppi->ppi_rows = 0;
2036 ppi->ppi_clauses = NIL;
2037 ppi->ppi_serials = NULL;
2038 appendrel->ppilist = lappend(appendrel->ppilist, ppi);
2039
2040 return ppi;
2041}
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:412
ParamPathInfo * find_param_path_info(RelOptInfo *rel, Relids required_outer)
Definition relnode.c:2048

References Assert, bms_is_empty, bms_is_subset(), bms_overlap(), fb(), find_param_path_info(), lappend(), makeNode, and NIL.

Referenced by create_append_path().

◆ get_baserel_parampathinfo()

ParamPathInfo * get_baserel_parampathinfo ( PlannerInfo root,
RelOptInfo baserel,
Relids  required_outer 
)
extern

Definition at line 1704 of file relnode.c.

1706{
1709 List *pclauses;
1710 List *eqclauses;
1712 double rows;
1713 ListCell *lc;
1714
1715 /* If rel has LATERAL refs, every path for it should account for them */
1716 Assert(bms_is_subset(baserel->lateral_relids, required_outer));
1717
1718 /* Unparameterized paths have no ParamPathInfo */
1720 return NULL;
1721
1723
1724 /* If we already have a PPI for this parameterization, just return it */
1726 return ppi;
1727
1728 /*
1729 * Identify all joinclauses that are movable to this base rel given this
1730 * parameterization.
1731 */
1733 pclauses = NIL;
1734 foreach(lc, baserel->joininfo)
1735 {
1736 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1737
1739 baserel->relids,
1740 joinrelids))
1741 pclauses = lappend(pclauses, rinfo);
1742 }
1743
1744 /*
1745 * Add in joinclauses generated by EquivalenceClasses, too. (These
1746 * necessarily satisfy join_clause_is_movable_into; but in assert-enabled
1747 * builds, let's verify that.)
1748 */
1750 joinrelids,
1752 baserel,
1753 NULL);
1754#ifdef USE_ASSERT_CHECKING
1755 foreach(lc, eqclauses)
1756 {
1757 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1758
1760 baserel->relids,
1761 joinrelids));
1762 }
1763#endif
1765
1766 /* Compute set of serial numbers of the enforced clauses */
1767 pserials = NULL;
1768 foreach(lc, pclauses)
1769 {
1770 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1771
1773 }
1774
1775 /* Estimate the number of rows returned by the parameterized scan */
1777
1778 /* And now we can build the ParamPathInfo */
1780 ppi->ppi_req_outer = required_outer;
1781 ppi->ppi_rows = rows;
1782 ppi->ppi_clauses = pclauses;
1783 ppi->ppi_serials = pserials;
1784 baserel->ppilist = lappend(baserel->ppilist, ppi);
1785
1786 return ppi;
1787}
double get_parameterized_baserel_size(PlannerInfo *root, RelOptInfo *rel, List *param_clauses)
Definition costsize.c:5522
List * generate_join_implied_equalities(PlannerInfo *root, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
bool join_clause_is_movable_into(RestrictInfo *rinfo, Relids currentrelids, Relids current_and_outer)

References Assert, bms_add_member(), bms_is_empty, bms_is_subset(), bms_overlap(), bms_union(), fb(), find_param_path_info(), generate_join_implied_equalities(), get_parameterized_baserel_size(), join_clause_is_movable_into(), lappend(), lfirst, list_concat(), makeNode, NIL, RestrictInfo::rinfo_serial, and root.

Referenced by create_append_path(), create_bitmap_and_path(), create_bitmap_heap_path(), create_bitmap_or_path(), create_ctescan_path(), create_foreignscan_path(), create_functionscan_path(), create_gather_merge_path(), create_gather_path(), create_index_path(), create_namedtuplestorescan_path(), create_resultscan_path(), create_samplescan_path(), create_seqscan_path(), create_subqueryscan_path(), create_tablefuncscan_path(), create_tidrangescan_path(), create_tidscan_path(), create_valuesscan_path(), create_worktablescan_path(), postgresGetForeignPaths(), and reparameterize_path().

◆ get_joinrel_parampathinfo()

ParamPathInfo * get_joinrel_parampathinfo ( PlannerInfo root,
RelOptInfo joinrel,
Path outer_path,
Path inner_path,
SpecialJoinInfo sjinfo,
Relids  required_outer,
List **  restrict_clauses 
)
extern

Definition at line 1818 of file relnode.c.

1824{
1829 List *pclauses;
1830 List *eclauses;
1832 double rows;
1833 ListCell *lc;
1834
1835 /* If rel has LATERAL refs, every path for it should account for them */
1837
1838 /* Unparameterized paths have no ParamPathInfo or extra join clauses */
1840 return NULL;
1841
1843
1844 /*
1845 * Identify all joinclauses that are movable to this join rel given this
1846 * parameterization. These are the clauses that are movable into this
1847 * join, but not movable into either input path. Treat an unparameterized
1848 * input path as not accepting parameterized clauses (because it won't,
1849 * per the shortcut exit above), even though the joinclause movement rules
1850 * might allow the same clauses to be moved into a parameterized path for
1851 * that rel.
1852 */
1854 if (outer_path->param_info)
1855 outer_and_req = bms_union(outer_path->parent->relids,
1857 else
1858 outer_and_req = NULL; /* outer path does not accept parameters */
1859 if (inner_path->param_info)
1860 inner_and_req = bms_union(inner_path->parent->relids,
1862 else
1863 inner_and_req = NULL; /* inner path does not accept parameters */
1864
1865 pclauses = NIL;
1866 foreach(lc, joinrel->joininfo)
1867 {
1868 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1869
1871 joinrel->relids,
1872 join_and_req) &&
1874 outer_path->parent->relids,
1875 outer_and_req) &&
1877 inner_path->parent->relids,
1879 pclauses = lappend(pclauses, rinfo);
1880 }
1881
1882 /* Consider joinclauses generated by EquivalenceClasses, too */
1886 joinrel,
1887 NULL);
1888 /* We only want ones that aren't movable to lower levels */
1889 dropped_ecs = NIL;
1890 foreach(lc, eclauses)
1891 {
1892 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1893
1895 joinrel->relids,
1896 join_and_req));
1898 outer_path->parent->relids,
1900 continue; /* drop if movable into LHS */
1902 inner_path->parent->relids,
1904 {
1905 /* drop if movable into RHS, but remember EC for use below */
1906 Assert(rinfo->left_ec == rinfo->right_ec);
1907 dropped_ecs = lappend(dropped_ecs, rinfo->left_ec);
1908 continue;
1909 }
1910 pclauses = lappend(pclauses, rinfo);
1911 }
1912
1913 /*
1914 * EquivalenceClasses are harder to deal with than we could wish, because
1915 * of the fact that a given EC can generate different clauses depending on
1916 * context. Suppose we have an EC {X.X, Y.Y, Z.Z} where X and Y are the
1917 * LHS and RHS of the current join and Z is in required_outer, and further
1918 * suppose that the inner_path is parameterized by both X and Z. The code
1919 * above will have produced either Z.Z = X.X or Z.Z = Y.Y from that EC,
1920 * and in the latter case will have discarded it as being movable into the
1921 * RHS. However, the EC machinery might have produced either Y.Y = X.X or
1922 * Y.Y = Z.Z as the EC enforcement clause within the inner_path; it will
1923 * not have produced both, and we can't readily tell from here which one
1924 * it did pick. If we add no clause to this join, we'll end up with
1925 * insufficient enforcement of the EC; either Z.Z or X.X will fail to be
1926 * constrained to be equal to the other members of the EC. (When we come
1927 * to join Z to this X/Y path, we will certainly drop whichever EC clause
1928 * is generated at that join, so this omission won't get fixed later.)
1929 *
1930 * To handle this, for each EC we discarded such a clause from, try to
1931 * generate a clause connecting the required_outer rels to the join's LHS
1932 * ("Z.Z = X.X" in the terms of the above example). If successful, and if
1933 * the clause can't be moved to the LHS, add it to the current join's
1934 * restriction clauses. (If an EC cannot generate such a clause then it
1935 * has nothing that needs to be enforced here, while if the clause can be
1936 * moved into the LHS then it should have been enforced within that path.)
1937 *
1938 * Note that we don't need similar processing for ECs whose clause was
1939 * considered to be movable into the LHS, because the LHS can't refer to
1940 * the RHS so there is no comparable ambiguity about what it might
1941 * actually be enforcing internally.
1942 */
1943 if (dropped_ecs)
1944 {
1946
1947 real_outer_and_req = bms_union(outer_path->parent->relids,
1949 eclauses =
1954 outer_path->parent);
1955 foreach(lc, eclauses)
1956 {
1957 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1958
1960 outer_path->parent->relids,
1962 if (!join_clause_is_movable_into(rinfo,
1963 outer_path->parent->relids,
1965 pclauses = lappend(pclauses, rinfo);
1966 }
1967 }
1968
1969 /*
1970 * Now, attach the identified moved-down clauses to the caller's
1971 * restrict_clauses list. By using list_concat in this order, we leave
1972 * the original list structure of restrict_clauses undamaged.
1973 */
1975
1976 /* If we already have a PPI for this parameterization, just return it */
1977 if ((ppi = find_param_path_info(joinrel, required_outer)))
1978 return ppi;
1979
1980 /* Estimate the number of rows returned by the parameterized join */
1981 rows = get_parameterized_joinrel_size(root, joinrel,
1982 outer_path,
1983 inner_path,
1984 sjinfo,
1986
1987 /*
1988 * And now we can build the ParamPathInfo. No point in saving the
1989 * input-pair-dependent clause list, though.
1990 *
1991 * Note: in GEQO mode, we'll be called in a temporary memory context, but
1992 * the joinrel structure is there too, so no problem.
1993 */
1995 ppi->ppi_req_outer = required_outer;
1996 ppi->ppi_rows = rows;
1997 ppi->ppi_clauses = NIL;
1998 ppi->ppi_serials = NULL;
1999 joinrel->ppilist = lappend(joinrel->ppilist, ppi);
2000
2001 return ppi;
2002}
double get_parameterized_joinrel_size(PlannerInfo *root, RelOptInfo *rel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, List *restrict_clauses)
Definition costsize.c:5603
List * generate_join_implied_equalities_for_ecs(PlannerInfo *root, List *eclasses, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel)

References Assert, bms_is_empty, bms_is_subset(), bms_overlap(), bms_union(), fb(), find_param_path_info(), generate_join_implied_equalities(), generate_join_implied_equalities_for_ecs(), get_parameterized_joinrel_size(), join_clause_is_movable_into(), RelOptInfo::joininfo, lappend(), RelOptInfo::lateral_relids, lfirst, list_concat(), makeNode, NIL, PATH_REQ_OUTER, RelOptInfo::ppilist, RelOptInfo::relids, and root.

Referenced by create_hashjoin_path(), create_mergejoin_path(), and create_nestloop_path().

◆ get_param_path_clause_serials()

Bitmapset * get_param_path_clause_serials ( Path path)
extern

Definition at line 2069 of file relnode.c.

2070{
2071 if (path->param_info == NULL)
2072 return NULL; /* not parameterized */
2073
2074 /*
2075 * We don't currently support parameterized MergeAppend paths, as
2076 * explained in the comments for generate_orderedappend_paths.
2077 */
2078 Assert(!IsA(path, MergeAppendPath));
2079
2080 if (IsA(path, NestPath) ||
2081 IsA(path, MergePath) ||
2082 IsA(path, HashPath))
2083 {
2084 /*
2085 * For a join path, combine clauses enforced within either input path
2086 * with those enforced as joinrestrictinfo in this path. Note that
2087 * joinrestrictinfo may include some non-pushed-down clauses, but for
2088 * current purposes it's okay if we include those in the result. (To
2089 * be more careful, we could check for clause_relids overlapping the
2090 * path parameterization, but it's not worth the cycles for now.)
2091 */
2092 JoinPath *jpath = (JoinPath *) path;
2094 ListCell *lc;
2095
2096 pserials = NULL;
2101 foreach(lc, jpath->joinrestrictinfo)
2102 {
2103 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2104
2106 }
2107 return pserials;
2108 }
2109 else if (IsA(path, AppendPath))
2110 {
2111 /*
2112 * For an appendrel, take the intersection of the sets of clauses
2113 * enforced in each input path.
2114 */
2115 AppendPath *apath = (AppendPath *) path;
2117 ListCell *lc;
2118
2119 pserials = NULL;
2120 foreach(lc, apath->subpaths)
2121 {
2122 Path *subpath = (Path *) lfirst(lc);
2124
2126 if (lc == list_head(apath->subpaths))
2128 else
2130 }
2131 return pserials;
2132 }
2133 else
2134 {
2135 /*
2136 * Otherwise, it's a baserel path and we can use the
2137 * previously-computed set of serial numbers.
2138 */
2139 return path->param_info->ppi_serials;
2140 }
2141}
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1093
static ListCell * list_head(const List *l)
Definition pg_list.h:128
Path * outerjoinpath
Definition pathnodes.h:2392
Path * innerjoinpath
Definition pathnodes.h:2393
List * joinrestrictinfo
Definition pathnodes.h:2395

References Assert, bms_add_member(), bms_add_members(), bms_copy(), bms_int_members(), fb(), get_param_path_clause_serials(), JoinPath::innerjoinpath, IsA, JoinPath::joinrestrictinfo, lfirst, list_head(), JoinPath::outerjoinpath, RestrictInfo::rinfo_serial, and subpath().

Referenced by create_nestloop_path(), and get_param_path_clause_serials().

◆ min_join_parameterization()

Relids min_join_parameterization ( PlannerInfo root,
Relids  joinrelids,
RelOptInfo outer_rel,
RelOptInfo inner_rel 
)
extern

Definition at line 1181 of file relnode.c.

1185{
1186 Relids result;
1187
1188 /*
1189 * Basically we just need the union of the inputs' lateral_relids, less
1190 * whatever is already in the join.
1191 *
1192 * It's not immediately obvious that this is a valid way to compute the
1193 * result, because it might seem that we're ignoring possible lateral refs
1194 * of PlaceHolderVars that are due to be computed at the join but not in
1195 * either input. However, because create_lateral_join_info() already
1196 * charged all such PHV refs to each member baserel of the join, they'll
1197 * be accounted for already in the inputs' lateral_relids. Likewise, we
1198 * do not need to worry about doing transitive closure here, because that
1199 * was already accounted for in the original baserel lateral_relids.
1200 */
1201 result = bms_union(outer_rel->lateral_relids, inner_rel->lateral_relids);
1202 result = bms_del_members(result, joinrelids);
1203 return result;
1204}

References bms_del_members(), bms_union(), and fb().

Referenced by build_join_rel(), and join_is_legal().

◆ path_is_reparameterizable_by_child()

bool path_is_reparameterizable_by_child ( Path path,
RelOptInfo child_rel 
)
extern

Definition at line 4382 of file pathnode.c.

4383{
4384#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE(path) \
4385do { \
4386 if (!path_is_reparameterizable_by_child(path, child_rel)) \
4387 return false; \
4388} while(0)
4389
4390#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE(pathlist) \
4391do { \
4392 if (!pathlist_is_reparameterizable_by_child(pathlist, child_rel)) \
4393 return false; \
4394} while(0)
4395
4396 /*
4397 * If the path is not parameterized by the parent of the given relation,
4398 * it doesn't need reparameterization.
4399 */
4400 if (!path->param_info ||
4401 !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4402 return true;
4403
4404 /*
4405 * Check that the path type is one that reparameterize_path_by_child() can
4406 * handle, and recursively check subpaths.
4407 */
4408 switch (nodeTag(path))
4409 {
4410 case T_Path:
4411 case T_IndexPath:
4412 break;
4413
4414 case T_BitmapHeapPath:
4415 {
4417
4419 }
4420 break;
4421
4422 case T_BitmapAndPath:
4423 {
4425
4427 }
4428 break;
4429
4430 case T_BitmapOrPath:
4431 {
4432 BitmapOrPath *bopath = (BitmapOrPath *) path;
4433
4435 }
4436 break;
4437
4438 case T_ForeignPath:
4439 {
4440 ForeignPath *fpath = (ForeignPath *) path;
4441
4442 if (fpath->fdw_outerpath)
4444 }
4445 break;
4446
4447 case T_CustomPath:
4448 {
4449 CustomPath *cpath = (CustomPath *) path;
4450
4452 }
4453 break;
4454
4455 case T_NestPath:
4456 case T_MergePath:
4457 case T_HashPath:
4458 {
4459 JoinPath *jpath = (JoinPath *) path;
4460
4463 }
4464 break;
4465
4466 case T_AppendPath:
4467 {
4468 AppendPath *apath = (AppendPath *) path;
4469
4471 }
4472 break;
4473
4474 case T_MaterialPath:
4475 {
4476 MaterialPath *mpath = (MaterialPath *) path;
4477
4479 }
4480 break;
4481
4482 case T_MemoizePath:
4483 {
4484 MemoizePath *mpath = (MemoizePath *) path;
4485
4487 }
4488 break;
4489
4490 case T_GatherPath:
4491 {
4492 GatherPath *gpath = (GatherPath *) path;
4493
4495 }
4496 break;
4497
4498 default:
4499 /* We don't know how to reparameterize this path. */
4500 return false;
4501 }
4502
4503 return true;
4504}
#define nodeTag(nodeptr)
Definition nodes.h:139
#define REJECT_IF_PATH_LIST_NOT_REPARAMETERIZABLE(pathlist)
#define REJECT_IF_PATH_NOT_REPARAMETERIZABLE(path)

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

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

◆ reparameterize_path()

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

Definition at line 3916 of file pathnode.c.

3919{
3920 RelOptInfo *rel = path->parent;
3921
3922 /* Can only increase, not decrease, path's parameterization */
3924 return NULL;
3925 switch (path->pathtype)
3926 {
3927 case T_SeqScan:
3928 return create_seqscan_path(root, rel, required_outer, 0);
3929 case T_SampleScan:
3931 case T_IndexScan:
3932 case T_IndexOnlyScan:
3933 {
3934 IndexPath *ipath = (IndexPath *) path;
3936
3937 /*
3938 * We can't use create_index_path directly, and would not want
3939 * to because it would re-compute the indexqual conditions
3940 * which is wasted effort. Instead we hack things a bit:
3941 * flat-copy the path node, revise its param_info, and redo
3942 * the cost estimate.
3943 */
3944 memcpy(newpath, ipath, sizeof(IndexPath));
3945 newpath->path.param_info =
3948 return (Path *) newpath;
3949 }
3950 case T_BitmapHeapScan:
3951 {
3953
3955 rel,
3956 bpath->bitmapqual,
3958 loop_count, 0);
3959 }
3960 case T_SubqueryScan:
3961 {
3962 SubqueryScanPath *spath = (SubqueryScanPath *) path;
3963 Path *subpath = spath->subpath;
3964 bool trivial_pathtarget;
3965
3966 /*
3967 * If existing node has zero extra cost, we must have decided
3968 * its target is trivial. (The converse is not true, because
3969 * it might have a trivial target but quals to enforce; but in
3970 * that case the new node will too, so it doesn't matter
3971 * whether we get the right answer here.)
3972 */
3974 (subpath->total_cost == spath->path.total_cost);
3975
3977 rel,
3978 subpath,
3980 spath->path.pathkeys,
3982 }
3983 case T_Result:
3984 /* Supported only for RTE_RESULT scan paths */
3985 if (IsA(path, Path))
3987 break;
3988 case T_Append:
3989 {
3990 AppendPath *apath = (AppendPath *) path;
3992 int i;
3993 ListCell *lc;
3994
3995 new_append.child_append_relid_sets = apath->child_append_relid_sets;
3996
3997 /* Reparameterize the children */
3998 i = 0;
3999 foreach(lc, apath->subpaths)
4000 {
4001 Path *spath = (Path *) lfirst(lc);
4002
4003 spath = reparameterize_path(root, spath,
4005 loop_count);
4006 if (spath == NULL)
4007 return NULL;
4008 /* We have to re-split the regular and partial paths */
4009 if (i < apath->first_partial_path)
4010 new_append.subpaths = lappend(new_append.subpaths, spath);
4011 else
4012 new_append.partial_subpaths = lappend(new_append.partial_subpaths, spath);
4013 i++;
4014 }
4015 return (Path *)
4017 apath->path.pathkeys, required_outer,
4018 apath->path.parallel_workers,
4019 apath->path.parallel_aware,
4020 -1);
4021 }
4022 case T_Material:
4023 {
4024 MaterialPath *mpath = (MaterialPath *) path;
4025 Path *spath = mpath->subpath;
4026 bool enabled;
4027
4028 spath = reparameterize_path(root, spath,
4030 loop_count);
4031 if (spath == NULL)
4032 return NULL;
4033 enabled =
4034 (mpath->path.disabled_nodes <= spath->disabled_nodes);
4035 return (Path *) create_material_path(rel, spath, enabled);
4036 }
4037 case T_Memoize:
4038 {
4039 MemoizePath *mpath = (MemoizePath *) path;
4040 Path *spath = mpath->subpath;
4041
4042 spath = reparameterize_path(root, spath,
4044 loop_count);
4045 if (spath == NULL)
4046 return NULL;
4047 return (Path *) create_memoize_path(root, rel,
4048 spath,
4049 mpath->param_exprs,
4050 mpath->hash_operators,
4051 mpath->singlerow,
4052 mpath->binary_mode,
4053 mpath->est_calls);
4054 }
4055 default:
4056 break;
4057 }
4058 return NULL;
4059}
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:1746
MaterialPath * create_material_path(RelOptInfo *rel, Path *subpath, bool enabled)
Definition pathnode.c:1712
Path * create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
Definition pathnode.c:1026
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
Definition pathnode.c:1909
BitmapHeapPath * create_bitmap_heap_path(PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
Definition pathnode.c:1149
Path * create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Definition pathnode.c:1051
Path * create_resultscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
Definition pathnode.c:2069
AppendPath * create_append_path(PlannerInfo *root, RelOptInfo *rel, AppendPathInput input, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
Definition pathnode.c:1352
Path * reparameterize_path(PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
Definition pathnode.c:3916

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

Referenced by get_cheapest_parameterized_child_path(), and reparameterize_path().

◆ reparameterize_path_by_child()

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

Definition at line 4086 of file pathnode.c.

4088{
4089 Path *new_path;
4093
4094#define ADJUST_CHILD_ATTRS(node) \
4095 ((node) = (void *) adjust_appendrel_attrs_multilevel(root, \
4096 (Node *) (node), \
4097 child_rel, \
4098 child_rel->top_parent))
4099
4100#define REPARAMETERIZE_CHILD_PATH(path) \
4101do { \
4102 (path) = reparameterize_path_by_child(root, (path), child_rel); \
4103 if ((path) == NULL) \
4104 return NULL; \
4105} while(0)
4106
4107#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
4108do { \
4109 if ((pathlist) != NIL) \
4110 { \
4111 (pathlist) = reparameterize_pathlist_by_child(root, (pathlist), \
4112 child_rel); \
4113 if ((pathlist) == NIL) \
4114 return NULL; \
4115 } \
4116} while(0)
4117
4118 /*
4119 * If the path is not parameterized by the parent of the given relation,
4120 * it doesn't need reparameterization.
4121 */
4122 if (!path->param_info ||
4123 !bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
4124 return path;
4125
4126 /*
4127 * If possible, reparameterize the given path.
4128 *
4129 * This function is currently only applied to the inner side of a nestloop
4130 * join that is being partitioned by the partitionwise-join code. Hence,
4131 * we need only support path types that plausibly arise in that context.
4132 * (In particular, supporting sorted path types would be a waste of code
4133 * and cycles: even if we translated them here, they'd just lose in
4134 * subsequent cost comparisons.) If we do see an unsupported path type,
4135 * that just means we won't be able to generate a partitionwise-join plan
4136 * using that path type.
4137 */
4138 switch (nodeTag(path))
4139 {
4140 case T_Path:
4141 new_path = path;
4142 ADJUST_CHILD_ATTRS(new_path->parent->baserestrictinfo);
4143 if (path->pathtype == T_SampleScan)
4144 {
4145 Index scan_relid = path->parent->relid;
4147
4148 /* it should be a base rel with a tablesample clause... */
4149 Assert(scan_relid > 0);
4151 Assert(rte->rtekind == RTE_RELATION);
4152 Assert(rte->tablesample != NULL);
4153
4154 ADJUST_CHILD_ATTRS(rte->tablesample);
4155 }
4156 break;
4157
4158 case T_IndexPath:
4159 {
4160 IndexPath *ipath = (IndexPath *) path;
4161
4162 ADJUST_CHILD_ATTRS(ipath->indexinfo->indrestrictinfo);
4163 ADJUST_CHILD_ATTRS(ipath->indexclauses);
4164 new_path = (Path *) ipath;
4165 }
4166 break;
4167
4168 case T_BitmapHeapPath:
4169 {
4171
4172 ADJUST_CHILD_ATTRS(bhpath->path.parent->baserestrictinfo);
4173 REPARAMETERIZE_CHILD_PATH(bhpath->bitmapqual);
4174 new_path = (Path *) bhpath;
4175 }
4176 break;
4177
4178 case T_BitmapAndPath:
4179 {
4181
4183 new_path = (Path *) bapath;
4184 }
4185 break;
4186
4187 case T_BitmapOrPath:
4188 {
4189 BitmapOrPath *bopath = (BitmapOrPath *) path;
4190
4192 new_path = (Path *) bopath;
4193 }
4194 break;
4195
4196 case T_ForeignPath:
4197 {
4198 ForeignPath *fpath = (ForeignPath *) path;
4200
4201 ADJUST_CHILD_ATTRS(fpath->path.parent->baserestrictinfo);
4202 if (fpath->fdw_outerpath)
4203 REPARAMETERIZE_CHILD_PATH(fpath->fdw_outerpath);
4204 if (fpath->fdw_restrictinfo)
4205 ADJUST_CHILD_ATTRS(fpath->fdw_restrictinfo);
4206
4207 /* Hand over to FDW if needed. */
4208 rfpc_func =
4209 path->parent->fdwroutine->ReparameterizeForeignPathByChild;
4210 if (rfpc_func)
4211 fpath->fdw_private = rfpc_func(root, fpath->fdw_private,
4212 child_rel);
4213 new_path = (Path *) fpath;
4214 }
4215 break;
4216
4217 case T_CustomPath:
4218 {
4219 CustomPath *cpath = (CustomPath *) path;
4220
4221 ADJUST_CHILD_ATTRS(cpath->path.parent->baserestrictinfo);
4223 if (cpath->custom_restrictinfo)
4224 ADJUST_CHILD_ATTRS(cpath->custom_restrictinfo);
4225 if (cpath->methods &&
4226 cpath->methods->ReparameterizeCustomPathByChild)
4227 cpath->custom_private =
4228 cpath->methods->ReparameterizeCustomPathByChild(root,
4229 cpath->custom_private,
4230 child_rel);
4231 new_path = (Path *) cpath;
4232 }
4233 break;
4234
4235 case T_NestPath:
4236 {
4237 NestPath *npath = (NestPath *) path;
4238 JoinPath *jpath = (JoinPath *) npath;
4239
4243 new_path = (Path *) npath;
4244 }
4245 break;
4246
4247 case T_MergePath:
4248 {
4249 MergePath *mpath = (MergePath *) path;
4250 JoinPath *jpath = (JoinPath *) mpath;
4251
4255 ADJUST_CHILD_ATTRS(mpath->path_mergeclauses);
4256 new_path = (Path *) mpath;
4257 }
4258 break;
4259
4260 case T_HashPath:
4261 {
4262 HashPath *hpath = (HashPath *) path;
4263 JoinPath *jpath = (JoinPath *) hpath;
4264
4268 ADJUST_CHILD_ATTRS(hpath->path_hashclauses);
4269 new_path = (Path *) hpath;
4270 }
4271 break;
4272
4273 case T_AppendPath:
4274 {
4275 AppendPath *apath = (AppendPath *) path;
4276
4278 new_path = (Path *) apath;
4279 }
4280 break;
4281
4282 case T_MaterialPath:
4283 {
4284 MaterialPath *mpath = (MaterialPath *) path;
4285
4287 new_path = (Path *) mpath;
4288 }
4289 break;
4290
4291 case T_MemoizePath:
4292 {
4293 MemoizePath *mpath = (MemoizePath *) path;
4294
4296 ADJUST_CHILD_ATTRS(mpath->param_exprs);
4297 new_path = (Path *) mpath;
4298 }
4299 break;
4300
4301 case T_GatherPath:
4302 {
4303 GatherPath *gpath = (GatherPath *) path;
4304
4306 new_path = (Path *) gpath;
4307 }
4308 break;
4309
4310 default:
4311 /* We don't know how to reparameterize this path. */
4312 return NULL;
4313 }
4314
4315 /*
4316 * Adjust the parameterization information, which refers to the topmost
4317 * parent. The topmost parent can be multiple levels away from the given
4318 * child, hence use multi-level expression adjustment routines.
4319 */
4320 old_ppi = new_path->param_info;
4323 child_rel,
4324 child_rel->top_parent);
4325
4326 /* If we already have a PPI for this parameterization, just return it */
4328
4329 /*
4330 * If not, build a new one and link it to the list of PPIs. For the same
4331 * reason as explained in mark_dummy_rel(), allocate new PPI in the same
4332 * context the given RelOptInfo is in.
4333 */
4334 if (new_ppi == NULL)
4335 {
4336 MemoryContext oldcontext;
4337 RelOptInfo *rel = path->parent;
4338
4340
4342 new_ppi->ppi_req_outer = bms_copy(required_outer);
4343 new_ppi->ppi_rows = old_ppi->ppi_rows;
4344 new_ppi->ppi_clauses = old_ppi->ppi_clauses;
4345 ADJUST_CHILD_ATTRS(new_ppi->ppi_clauses);
4346 new_ppi->ppi_serials = bms_copy(old_ppi->ppi_serials);
4347 rel->ppilist = lappend(rel->ppilist, new_ppi);
4348
4349 MemoryContextSwitchTo(oldcontext);
4350 }
4352
4353 new_path->param_info = new_ppi;
4354
4355 /*
4356 * Adjust the path target if the parent of the outer relation is
4357 * referenced in the targetlist. This can happen when only the parent of
4358 * outer relation is laterally referenced in this relation.
4359 */
4360 if (bms_overlap(path->parent->lateral_relids,
4361 child_rel->top_parent_relids))
4362 {
4363 new_path->pathtarget = copy_pathtarget(new_path->pathtarget);
4364 ADJUST_CHILD_ATTRS(new_path->pathtarget->exprs);
4365 }
4366
4367 return new_path;
4368}
Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition appendinfo.c:664
void bms_free(Bitmapset *a)
Definition bitmapset.c:239
List *(* ReparameterizeForeignPathByChild_function)(PlannerInfo *root, List *fdw_private, RelOptInfo *child_rel)
Definition fdwapi.h:182
MemoryContext GetMemoryChunkContext(void *pointer)
Definition mcxt.c:756
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define REPARAMETERIZE_CHILD_PATH_LIST(pathlist)
#define REPARAMETERIZE_CHILD_PATH(path)
#define ADJUST_CHILD_ATTRS(node)
#define planner_rt_fetch(rti, root)
Definition pathnodes.h:692
PathTarget * copy_pathtarget(PathTarget *src)
Definition tlist.c:666

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

Referenced by create_nestloop_plan(), and reparameterize_pathlist_by_child().

◆ set_cheapest()

void set_cheapest ( RelOptInfo parent_rel)
extern

Definition at line 268 of file pathnode.c.

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

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

Referenced by apply_scanjoin_target_to_paths(), create_distinct_paths(), create_grouping_paths(), create_ordinary_grouping_paths(), create_partial_distinct_paths(), create_partial_unique_paths(), create_partitionwise_grouping_paths(), create_unique_paths(), create_window_paths(), generate_partitionwise_join_paths(), mark_dummy_rel(), merge_clump(), postprocess_setop_rel(), query_planner(), set_dummy_rel_pathlist(), set_grouped_rel_pathlist(), set_rel_pathlist(), standard_join_search(), and subquery_planner().

◆ setup_simple_rel_arrays()

void setup_simple_rel_arrays ( PlannerInfo root)
extern

Definition at line 114 of file relnode.c.

115{
116 int size;
117 Index rti;
118 ListCell *lc;
119
120 /* Arrays are accessed using RT indexes (1..N) */
121 size = list_length(root->parse->rtable) + 1;
122 root->simple_rel_array_size = size;
123
124 /*
125 * simple_rel_array is initialized to all NULLs, since no RelOptInfos
126 * exist yet. It'll be filled by later calls to build_simple_rel().
127 */
128 root->simple_rel_array = (RelOptInfo **)
129 palloc0_array(RelOptInfo *, size);
130
131 /* simple_rte_array is an array equivalent of the rtable list */
132 root->simple_rte_array = (RangeTblEntry **)
134 rti = 1;
135 foreach(lc, root->parse->rtable)
136 {
138
139 root->simple_rte_array[rti++] = rte;
140 }
141
142 /* append_rel_array is not needed if there are no AppendRelInfos */
143 if (root->append_rel_list == NIL)
144 {
145 root->append_rel_array = NULL;
146 return;
147 }
148
149 root->append_rel_array = (AppendRelInfo **)
151
152 /*
153 * append_rel_array is filled with any already-existing AppendRelInfos,
154 * which currently could only come from UNION ALL flattening. We might
155 * add more later during inheritance expansion, but it's the
156 * responsibility of the expansion code to update the array properly.
157 */
158 foreach(lc, root->append_rel_list)
159 {
161 int child_relid = appinfo->child_relid;
162
163 /* Sanity check */
164 Assert(child_relid < size);
165
166 if (root->append_rel_array[child_relid])
167 elog(ERROR, "child relation already exists");
168
169 root->append_rel_array[child_relid] = appinfo;
170 }
171}

References Assert, elog, ERROR, fb(), lfirst, lfirst_node, list_length(), NIL, palloc0_array, and root.

Referenced by plan_cluster_use_sort(), plan_create_index_workers(), plan_set_operations(), and query_planner().

Variable Documentation

◆ build_simple_rel_hook

PGDLLIMPORT build_simple_rel_hook_type build_simple_rel_hook
extern

Definition at line 51 of file relnode.c.

Referenced by build_simple_rel(), and pgpa_planner_install_hooks().

◆ joinrel_setup_hook

PGDLLIMPORT joinrel_setup_hook_type joinrel_setup_hook
extern

Definition at line 54 of file relnode.c.

Referenced by build_child_join_rel(), build_join_rel(), and pgpa_planner_install_hooks().