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.

Typedefs

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 total_cost, List *pathkeys)
 
Pathcreate_seqscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
 
Pathcreate_samplescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
IndexPathcreate_index_path (PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
 
BitmapHeapPathcreate_bitmap_heap_path (PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
 
BitmapAndPathcreate_bitmap_and_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
BitmapOrPathcreate_bitmap_or_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
TidPathcreate_tidscan_path (PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
 
TidRangePathcreate_tidrangescan_path (PlannerInfo *root, RelOptInfo *rel, List *tidrangequals, Relids required_outer, int parallel_workers)
 
AppendPathcreate_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *partial_subpaths, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath, bool enabled)
 
MemoizePathcreate_memoize_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, Cardinality est_calls)
 
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 joinrel_setup_hook_type joinrel_setup_hook
 

Typedef Documentation

◆ 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 22 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 /* Unless pathkeys are incompatible, keep just one of the two paths. */
823 {
824 if (unlikely(new_path->disabled_nodes != old_path->disabled_nodes))
825 {
826 if (new_path->disabled_nodes > old_path->disabled_nodes)
827 accept_new = false;
828 else
829 remove_old = true;
830 }
831 else if (new_path->total_cost > old_path->total_cost
833 {
834 /* New path costs more; keep it only if pathkeys are better. */
836 accept_new = false;
837 }
838 else if (old_path->total_cost > new_path->total_cost
840 {
841 /* Old path costs more; keep it only if pathkeys are better. */
843 remove_old = true;
844 }
845 else if (keyscmp == PATHKEYS_BETTER1)
846 {
847 /* Costs are about the same, new path has better pathkeys. */
848 remove_old = true;
849 }
850 else if (keyscmp == PATHKEYS_BETTER2)
851 {
852 /* Costs are about the same, old path has better pathkeys. */
853 accept_new = false;
854 }
855 else if (old_path->total_cost > new_path->total_cost * 1.0000000001)
856 {
857 /* Pathkeys are the same, and the old path costs more. */
858 remove_old = true;
859 }
860 else
861 {
862 /*
863 * Pathkeys are the same, and new path isn't materially
864 * cheaper.
865 */
866 accept_new = false;
867 }
868 }
869
870 /*
871 * Remove current element from partial_pathlist if dominated by new.
872 */
873 if (remove_old)
874 {
875 parent_rel->partial_pathlist =
876 foreach_delete_current(parent_rel->partial_pathlist, p1);
878 }
879 else
880 {
881 /* new belongs after this old path if it has cost >= old's */
882 if (new_path->total_cost >= old_path->total_cost)
884 }
885
886 /*
887 * If we found an old path that dominates new_path, we can quit
888 * scanning the partial_pathlist; we will not add new_path, and we
889 * assume new_path cannot dominate any later path.
890 */
891 if (!accept_new)
892 break;
893 }
894
895 if (accept_new)
896 {
897 /* Accept the new path: insert it at proper place */
898 parent_rel->partial_pathlist =
899 list_insert_nth(parent_rel->partial_pathlist, insert_at, new_path);
900 }
901 else
902 {
903 /* Reject and recycle the new path */
905 }
906}
#define Assert(condition)
Definition c.h:873
#define unlikely(x)
Definition c.h:412
List * list_insert_nth(List *list, int pos, void *datum)
Definition list.c:439
void pfree(void *pointer)
Definition mcxt.c:1616
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
PathKeysComparison compare_pathkeys(List *keys1, List *keys2)
Definition pathkeys.c:304
#define STD_FUZZ_FACTOR
Definition pathnode.c:47
PathKeysComparison
Definition paths.h:219
@ PATHKEYS_BETTER2
Definition paths.h:222
@ PATHKEYS_BETTER1
Definition paths.h:221
@ PATHKEYS_DIFFERENT
Definition paths.h:223
#define lfirst(lc)
Definition pg_list.h:172
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:391
static int fb(int x)

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

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

◆ add_partial_path_precheck()

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

Definition at line 919 of file pathnode.c.

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

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

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

◆ add_path()

void add_path ( RelOptInfo parent_rel,
Path new_path 
)
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
static PathCostComparison compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
Definition pathnode.c:181
PathCostComparison
Definition pathnode.c:35
@ COSTS_EQUAL
Definition pathnode.c:36
@ COSTS_BETTER1
Definition pathnode.c:37
@ COSTS_BETTER2
Definition pathnode.c:38
@ COSTS_DIFFERENT
Definition pathnode.c:39
#define PATH_REQ_OUTER(path)
Definition pathnodes.h:1995
#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 3792 of file pathnode.c.

3797{
3798 double input_rows = *rows;
3799 Cost input_startup_cost = *startup_cost;
3800 Cost input_total_cost = *total_cost;
3801
3802 if (offset_est != 0)
3803 {
3804 double offset_rows;
3805
3806 if (offset_est > 0)
3807 offset_rows = (double) offset_est;
3808 else
3810 if (offset_rows > *rows)
3811 offset_rows = *rows;
3812 if (input_rows > 0)
3813 *startup_cost +=
3816 *rows -= offset_rows;
3817 if (*rows < 1)
3818 *rows = 1;
3819 }
3820
3821 if (count_est != 0)
3822 {
3823 double count_rows;
3824
3825 if (count_est > 0)
3826 count_rows = (double) count_est;
3827 else
3829 if (count_rows > *rows)
3830 count_rows = *rows;
3831 if (input_rows > 0)
3832 *total_cost = *startup_cost +
3835 *rows = count_rows;
3836 if (*rows < 1)
3837 *rows = 1;
3838 }
3839}
double clamp_row_est(double nrows)
Definition costsize.c:213
double Cost
Definition nodes.h:261

References clamp_row_est(), and fb().

Referenced by create_limit_path(), and estimate_path_cost_size().

◆ apply_projection_to_path()

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

Definition at line 2640 of file pathnode.c.

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

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

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

◆ 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 1015 of file relnode.c.

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

489{
490 RelOptInfo *grouped_rel;
491
492 grouped_rel = makeNode(RelOptInfo);
493 memcpy(grouped_rel, rel, sizeof(RelOptInfo));
494
495 /*
496 * clear path info
497 */
498 grouped_rel->pathlist = NIL;
499 grouped_rel->ppilist = NIL;
500 grouped_rel->partial_pathlist = NIL;
501 grouped_rel->cheapest_startup_path = NULL;
502 grouped_rel->cheapest_total_path = NULL;
503 grouped_rel->cheapest_parameterized_paths = NIL;
504
505 /*
506 * clear partition info
507 */
508 grouped_rel->part_scheme = NULL;
509 grouped_rel->nparts = -1;
510 grouped_rel->boundinfo = NULL;
511 grouped_rel->partbounds_merged = false;
512 grouped_rel->partition_qual = NIL;
513 grouped_rel->part_rels = NULL;
514 grouped_rel->live_parts = NULL;
515 grouped_rel->all_partrels = NULL;
516 grouped_rel->partexprs = NULL;
517 grouped_rel->nullable_partexprs = NULL;
518 grouped_rel->consider_partitionwise_join = false;
519
520 /*
521 * clear size estimates
522 */
523 grouped_rel->rows = 0;
524
525 return grouped_rel;
526}

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 784 of file relnode.c.

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

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 437 of file relnode.c.

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

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 209 of file relnode.c.

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

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(), 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 2221 of file pathnode.c.

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

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

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

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

Referenced by try_hashjoin_path(), and try_mergejoin_path().

◆ compare_fractional_path_costs()

int compare_fractional_path_costs ( Path path1,
Path path2,
double  fraction 
)
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 3001 of file pathnode.c.

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

Definition at line 1299 of file pathnode.c.

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

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

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

◆ create_bitmap_and_path()

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

Definition at line 1129 of file pathnode.c.

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

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

Referenced by bitmap_and_cost_est(), and choose_bitmap_and().

◆ create_bitmap_heap_path()

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

Definition at line 1096 of file pathnode.c.

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

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

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

◆ create_bitmap_or_path()

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

Definition at line 1181 of file pathnode.c.

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

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

Referenced by generate_bitmap_or_paths().

◆ create_ctescan_path()

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

Definition at line 1961 of file pathnode.c.

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

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

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

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

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

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

◆ create_foreignscan_path()

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

Definition at line 2072 of file pathnode.c.

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

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

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

◆ create_functionscan_path()

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

Definition at line 1883 of file pathnode.c.

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

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

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

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

◆ create_gather_path()

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

Definition at line 1809 of file pathnode.c.

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

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

Referenced by generate_gather_paths(), and generate_union_paths().

◆ create_group_path()

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

Definition at line 2892 of file pathnode.c.

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

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

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

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

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

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

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

Referenced by try_hashjoin_path(), and try_partial_hashjoin_path().

◆ create_incremental_sort_path()

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

Definition at line 2799 of file pathnode.c.

2805{
2807 SortPath *pathnode = &sort->spath;
2808
2810 pathnode->path.parent = rel;
2811 /* Sort doesn't project, so use source path's pathtarget */
2812 pathnode->path.pathtarget = subpath->pathtarget;
2813 pathnode->path.param_info = subpath->param_info;
2814 pathnode->path.parallel_aware = false;
2815 pathnode->path.parallel_safe = rel->consider_parallel &&
2816 subpath->parallel_safe;
2817 pathnode->path.parallel_workers = subpath->parallel_workers;
2818 pathnode->path.pathkeys = pathkeys;
2819
2820 pathnode->subpath = subpath;
2821
2823 root, pathkeys, presorted_keys,
2824 subpath->disabled_nodes,
2825 subpath->startup_cost,
2826 subpath->total_cost,
2827 subpath->rows,
2828 subpath->pathtarget->width,
2829 0.0, /* XXX comparison_cost shouldn't be 0? */
2830 work_mem, limit_tuples);
2831
2832 sort->nPresortedCols = presorted_keys;
2833
2834 return sort;
2835}
Datum sort(PG_FUNCTION_ARGS)
Definition _int_op.c:198
void cost_incremental_sort(Path *path, PlannerInfo *root, List *pathkeys, int presorted_keys, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double input_tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition costsize.c:2053
NodeTag pathtype
Definition pathnodes.h:1951
Path path
Definition pathnodes.h:2507

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

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

◆ create_index_path()

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

Definition at line 1047 of file pathnode.c.

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

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

Referenced by build_index_paths(), and plan_cluster_use_sort().

◆ create_limit_path()

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

Definition at line 3736 of file pathnode.c.

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

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

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

◆ create_lockrows_path()

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

Definition at line 3574 of file pathnode.c.

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

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

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

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

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

Referenced by get_memoize_path(), and reparameterize_path().

◆ create_merge_append_path()

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

Definition at line 1470 of file pathnode.c.

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

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

Referenced by generate_orderedappend_paths(), and generate_union_paths().

◆ create_mergejoin_path()

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

Definition at line 2397 of file pathnode.c.

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

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

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

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

Referenced by preprocess_minmax_aggregates().

◆ create_modifytable_path()

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

Definition at line 3636 of file pathnode.c.

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

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

Referenced by grouping_planner().

◆ create_namedtuplestorescan_path()

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

Definition at line 1987 of file pathnode.c.

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

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

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

Referenced by try_nestloop_path(), and try_partial_nestloop_path().

◆ create_projection_path()

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

Definition at line 2531 of file pathnode.c.

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

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

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

◆ create_recursiveunion_path()

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

Definition at line 3529 of file pathnode.c.

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

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

Referenced by generate_recursion_path().

◆ create_rel_agg_info()

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

Definition at line 2680 of file relnode.c.

2682{
2683 ListCell *lc;
2684 RelAggInfo *result;
2685 PathTarget *agg_input;
2686 PathTarget *target;
2687 List *group_clauses = NIL;
2688 List *group_exprs = NIL;
2689
2690 /*
2691 * The lists of aggregate expressions and grouping expressions should have
2692 * been constructed.
2693 */
2694 Assert(root->agg_clause_list != NIL);
2695 Assert(root->group_expr_list != NIL);
2696
2697 /*
2698 * If this is a child rel, the grouped rel for its parent rel must have
2699 * been created if it can. So we can just use parent's RelAggInfo if
2700 * there is one, with appropriate variable substitutions.
2701 */
2702 if (IS_OTHER_REL(rel))
2703 {
2704 RelOptInfo *grouped_rel;
2705 RelAggInfo *agg_info;
2706
2707 grouped_rel = rel->top_parent->grouped_rel;
2708 if (grouped_rel == NULL)
2709 return NULL;
2710
2711 Assert(IS_GROUPED_REL(grouped_rel));
2712
2713 /* Must do multi-level transformation */
2714 agg_info = (RelAggInfo *)
2716 (Node *) grouped_rel->agg_info,
2717 rel,
2718 rel->top_parent);
2719
2720 agg_info->apply_agg_at = NULL; /* caller will change this later */
2721
2723 {
2724 agg_info->grouped_rows =
2726 rel->rows, NULL, NULL);
2727
2728 /*
2729 * The grouped paths for the given relation are considered useful
2730 * iff the average group size is no less than
2731 * min_eager_agg_group_size.
2732 */
2733 agg_info->agg_useful =
2734 (rel->rows / agg_info->grouped_rows) >= min_eager_agg_group_size;
2735 }
2736
2737 return agg_info;
2738 }
2739
2740 /* Check if it's possible to produce grouped paths for this relation. */
2742 return NULL;
2743
2744 /*
2745 * Create targets for the grouped paths and for the input paths of the
2746 * grouped paths.
2747 */
2748 target = create_empty_pathtarget();
2749 agg_input = create_empty_pathtarget();
2750
2751 /* ... and initialize these targets */
2752 if (!init_grouping_targets(root, rel, target, agg_input,
2753 &group_clauses, &group_exprs))
2754 return NULL;
2755
2756 /*
2757 * Eager aggregation is not applicable if there are no available grouping
2758 * expressions.
2759 */
2760 if (group_clauses == NIL)
2761 return NULL;
2762
2763 /* Add aggregates to the grouping target */
2764 foreach(lc, root->agg_clause_list)
2765 {
2767 Aggref *aggref;
2768
2769 Assert(IsA(ac_info->aggref, Aggref));
2770
2771 aggref = (Aggref *) copyObject(ac_info->aggref);
2773
2774 add_column_to_pathtarget(target, (Expr *) aggref, 0);
2775 }
2776
2777 /* Set the estimated eval cost and output width for both targets */
2779 set_pathtarget_cost_width(root, agg_input);
2780
2781 /* build the RelAggInfo result */
2782 result = makeNode(RelAggInfo);
2783 result->target = target;
2784 result->agg_input = agg_input;
2785 result->group_clauses = group_clauses;
2786 result->group_exprs = group_exprs;
2787 result->apply_agg_at = NULL; /* caller will change this later */
2788
2790 {
2792 rel->rows, NULL, NULL);
2793
2794 /*
2795 * The grouped paths for the given relation are considered useful iff
2796 * the average group size is no less than min_eager_agg_group_size.
2797 */
2798 result->agg_useful =
2799 (rel->rows / result->grouped_rows) >= min_eager_agg_group_size;
2800 }
2801
2802 return result;
2803}
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:592
PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
Definition costsize.c:6515
#define copyObject(obj)
Definition nodes.h:232
@ AGGSPLIT_INITIAL_SERIAL
Definition nodes.h:389
#define IS_GROUPED_REL(rel)
Definition pathnodes.h:1239
#define lfirst_node(type, lc)
Definition pg_list.h:176
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition planner.c:5816
static bool init_grouping_targets(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, PathTarget *agg_input, List **group_clauses, List **group_exprs)
Definition relnode.c:2890
static bool eager_aggregation_possible_for_relation(PlannerInfo *root, RelOptInfo *rel)
Definition relnode.c:2810
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition selfuncs.c:3771
List * group_exprs
Definition pathnodes.h:1281
List * group_clauses
Definition pathnodes.h:1279
struct PathTarget * agg_input
Definition pathnodes.h:1276
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 2013 of file pathnode.c.

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

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

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

Referenced by reparameterize_path(), and set_tablesample_rel_pathlist().

◆ create_seqscan_path()

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

Definition at line 981 of file pathnode.c.

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

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

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

◆ create_set_projection_path()

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

Definition at line 2729 of file pathnode.c.

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

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

Referenced by adjust_paths_for_srfs().

◆ create_setop_path()

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

Definition at line 3410 of file pathnode.c.

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

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

Referenced by generate_nonunion_paths().

◆ create_sort_path()

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

Definition at line 2848 of file pathnode.c.

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

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

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

◆ create_subqueryscan_path()

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

Definition at line 1853 of file pathnode.c.

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

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

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

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

Referenced by create_tidscan_paths().

◆ create_tidscan_path()

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

Definition at line 1233 of file pathnode.c.

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

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

Referenced by BuildParameterizedTidPaths(), and create_tidscan_paths().

◆ create_unique_path()

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

Definition at line 2949 of file pathnode.c.

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

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

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

◆ create_valuesscan_path()

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

Definition at line 1935 of file pathnode.c.

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

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

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

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

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

Referenced by set_worktable_pathlist().

◆ expand_planner_arrays()

void expand_planner_arrays ( PlannerInfo root,
int  add_size 
)
extern

Definition at line 180 of file relnode.c.

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

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 1606 of file relnode.c.

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

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 573 of file relnode.c.

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

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 555 of file relnode.c.

556{
557 /* use an unsigned comparison to prevent negative array element access */
558 if ((uint32) relid < (uint32) root->simple_rel_array_size)
559 return root->simple_rel_array[relid];
560 return NULL;
561}

References fb(), and root.

Referenced by all_rows_selectable().

◆ find_childrel_parents()

Relids find_childrel_parents ( PlannerInfo root,
RelOptInfo rel 
)
extern

Definition at line 1657 of file relnode.c.

1658{
1659 Relids result = NULL;
1660
1662 Assert(rel->relid > 0 && rel->relid < root->simple_rel_array_size);
1663
1664 do
1665 {
1666 AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
1668
1669 result = bms_add_member(result, prelid);
1670
1671 /* traverse up to the parent rel, loop if it's also a child rel */
1672 rel = find_base_rel(root, prelid);
1673 } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
1674
1676
1677 return result;
1678}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:814
unsigned int Index
Definition c.h:628
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition relnode.c:533
Index parent_relid
Definition pathnodes.h:3270

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 646 of file relnode.c.

647{
648 /*
649 * Switch to using hash lookup when list grows "too long". The threshold
650 * is arbitrary and is known only here.
651 */
652 if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
654
655 /*
656 * Use either hashtable lookup or linear search, as appropriate.
657 *
658 * Note: the seemingly redundant hashkey variable is used to avoid taking
659 * the address of relids; unless the compiler is exceedingly smart, doing
660 * so would force relids out of a register and thus probably slow down the
661 * list-search case.
662 */
663 if (root->join_rel_hash)
664 {
665 Relids hashkey = relids;
667
668 hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
669 &hashkey,
670 HASH_FIND,
671 NULL);
672 if (hentry)
673 return hentry->join_rel;
674 }
675 else
676 {
677 ListCell *l;
678
679 foreach(l, root->join_rel_list)
680 {
681 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
682
683 if (bms_equal(rel->relids, relids))
684 return rel;
685 }
686 }
687
688 return NULL;
689}
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:605
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 2037 of file relnode.c.

2038{
2039 ListCell *lc;
2040
2041 foreach(lc, rel->ppilist)
2042 {
2044
2045 if (bms_equal(ppi->ppi_req_outer, required_outer))
2046 return ppi;
2047 }
2048
2049 return NULL;
2050}

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 2004 of file relnode.c.

2005{
2007
2008 /* If rel has LATERAL refs, every path for it should account for them */
2009 Assert(bms_is_subset(appendrel->lateral_relids, required_outer));
2010
2011 /* Unparameterized paths have no ParamPathInfo */
2013 return NULL;
2014
2016
2017 /* If we already have a PPI for this parameterization, just return it */
2019 return ppi;
2020
2021 /* Else build the ParamPathInfo */
2023 ppi->ppi_req_outer = required_outer;
2024 ppi->ppi_rows = 0;
2025 ppi->ppi_clauses = NIL;
2026 ppi->ppi_serials = NULL;
2027 appendrel->ppilist = lappend(appendrel->ppilist, ppi);
2028
2029 return ppi;
2030}
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:2037

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 1693 of file relnode.c.

1695{
1698 List *pclauses;
1699 List *eqclauses;
1701 double rows;
1702 ListCell *lc;
1703
1704 /* If rel has LATERAL refs, every path for it should account for them */
1705 Assert(bms_is_subset(baserel->lateral_relids, required_outer));
1706
1707 /* Unparameterized paths have no ParamPathInfo */
1709 return NULL;
1710
1712
1713 /* If we already have a PPI for this parameterization, just return it */
1715 return ppi;
1716
1717 /*
1718 * Identify all joinclauses that are movable to this base rel given this
1719 * parameterization.
1720 */
1722 pclauses = NIL;
1723 foreach(lc, baserel->joininfo)
1724 {
1725 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1726
1728 baserel->relids,
1729 joinrelids))
1730 pclauses = lappend(pclauses, rinfo);
1731 }
1732
1733 /*
1734 * Add in joinclauses generated by EquivalenceClasses, too. (These
1735 * necessarily satisfy join_clause_is_movable_into; but in assert-enabled
1736 * builds, let's verify that.)
1737 */
1739 joinrelids,
1741 baserel,
1742 NULL);
1743#ifdef USE_ASSERT_CHECKING
1744 foreach(lc, eqclauses)
1745 {
1746 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1747
1749 baserel->relids,
1750 joinrelids));
1751 }
1752#endif
1754
1755 /* Compute set of serial numbers of the enforced clauses */
1756 pserials = NULL;
1757 foreach(lc, pclauses)
1758 {
1759 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1760
1762 }
1763
1764 /* Estimate the number of rows returned by the parameterized scan */
1766
1767 /* And now we can build the ParamPathInfo */
1769 ppi->ppi_req_outer = required_outer;
1770 ppi->ppi_rows = rows;
1771 ppi->ppi_clauses = pclauses;
1772 ppi->ppi_serials = pserials;
1773 baserel->ppilist = lappend(baserel->ppilist, ppi);
1774
1775 return ppi;
1776}
double get_parameterized_baserel_size(PlannerInfo *root, RelOptInfo *rel, List *param_clauses)
Definition costsize.c:5527
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 1807 of file relnode.c.

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

2059{
2060 if (path->param_info == NULL)
2061 return NULL; /* not parameterized */
2062
2063 /*
2064 * We don't currently support parameterized MergeAppend paths, as
2065 * explained in the comments for generate_orderedappend_paths.
2066 */
2067 Assert(!IsA(path, MergeAppendPath));
2068
2069 if (IsA(path, NestPath) ||
2070 IsA(path, MergePath) ||
2071 IsA(path, HashPath))
2072 {
2073 /*
2074 * For a join path, combine clauses enforced within either input path
2075 * with those enforced as joinrestrictinfo in this path. Note that
2076 * joinrestrictinfo may include some non-pushed-down clauses, but for
2077 * current purposes it's okay if we include those in the result. (To
2078 * be more careful, we could check for clause_relids overlapping the
2079 * path parameterization, but it's not worth the cycles for now.)
2080 */
2081 JoinPath *jpath = (JoinPath *) path;
2083 ListCell *lc;
2084
2085 pserials = NULL;
2090 foreach(lc, jpath->joinrestrictinfo)
2091 {
2092 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2093
2095 }
2096 return pserials;
2097 }
2098 else if (IsA(path, AppendPath))
2099 {
2100 /*
2101 * For an appendrel, take the intersection of the sets of clauses
2102 * enforced in each input path.
2103 */
2104 AppendPath *apath = (AppendPath *) path;
2106 ListCell *lc;
2107
2108 pserials = NULL;
2109 foreach(lc, apath->subpaths)
2110 {
2111 Path *subpath = (Path *) lfirst(lc);
2113
2115 if (lc == list_head(apath->subpaths))
2117 else
2119 }
2120 return pserials;
2121 }
2122 else
2123 {
2124 /*
2125 * Otherwise, it's a baserel path and we can use the
2126 * previously-computed set of serial numbers.
2127 */
2128 return path->param_info->ppi_serials;
2129 }
2130}
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1108
static ListCell * list_head(const List *l)
Definition pg_list.h:128
Path * outerjoinpath
Definition pathnodes.h:2374
Path * innerjoinpath
Definition pathnodes.h:2375
List * joinrestrictinfo
Definition pathnodes.h:2377

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 1170 of file relnode.c.

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

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

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

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

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

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

Referenced by get_cheapest_parameterized_child_path(), and reparameterize_path().

◆ reparameterize_path_by_child()

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

Definition at line 4029 of file pathnode.c.

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

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

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

◆ joinrel_setup_hook

PGDLLIMPORT joinrel_setup_hook_type joinrel_setup_hook
extern

Definition at line 51 of file relnode.c.

Referenced by build_child_join_rel(), and build_join_rel().