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

Go to the source code of this file.

Data Structures

struct  AppendPathInput
 

Typedefs

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

Functions

int compare_path_costs (Path *path1, Path *path2, CostSelector criterion)
 
int compare_fractional_path_costs (Path *path1, Path *path2, double fraction)
 
void set_cheapest (RelOptInfo *parent_rel)
 
void add_path (RelOptInfo *parent_rel, Path *new_path)
 
bool add_path_precheck (RelOptInfo *parent_rel, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer)
 
void add_partial_path (RelOptInfo *parent_rel, Path *new_path)
 
bool add_partial_path_precheck (RelOptInfo *parent_rel, int disabled_nodes, Cost total_cost, List *pathkeys)
 
Pathcreate_seqscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
 
Pathcreate_samplescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
IndexPathcreate_index_path (PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
 
BitmapHeapPathcreate_bitmap_heap_path (PlannerInfo *root, RelOptInfo *rel, Path *bitmapqual, Relids required_outer, double loop_count, int parallel_degree)
 
BitmapAndPathcreate_bitmap_and_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
BitmapOrPathcreate_bitmap_or_path (PlannerInfo *root, RelOptInfo *rel, List *bitmapquals)
 
TidPathcreate_tidscan_path (PlannerInfo *root, RelOptInfo *rel, List *tidquals, Relids required_outer)
 
TidRangePathcreate_tidrangescan_path (PlannerInfo *root, RelOptInfo *rel, List *tidrangequals, Relids required_outer, int parallel_workers)
 
AppendPathcreate_append_path (PlannerInfo *root, RelOptInfo *rel, AppendPathInput input, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
 
MergeAppendPathcreate_merge_append_path (PlannerInfo *root, RelOptInfo *rel, List *subpaths, List *child_append_relid_sets, List *pathkeys, Relids required_outer)
 
GroupResultPathcreate_group_result_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
 
MaterialPathcreate_material_path (RelOptInfo *rel, Path *subpath, bool enabled)
 
MemoizePathcreate_memoize_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *param_exprs, List *hash_operators, bool singlerow, bool binary_mode, Cardinality est_calls)
 
GatherPathcreate_gather_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, Relids required_outer, double *rows)
 
GatherMergePathcreate_gather_merge_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *pathkeys, Relids required_outer, double *rows)
 
SubqueryScanPathcreate_subqueryscan_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, bool trivial_pathtarget, List *pathkeys, Relids required_outer)
 
Pathcreate_functionscan_path (PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer)
 
Pathcreate_valuesscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_tablefuncscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_ctescan_path (PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer)
 
Pathcreate_namedtuplestorescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_resultscan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
Pathcreate_worktablescan_path (PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 
ForeignPathcreate_foreignscan_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
ForeignPathcreate_foreign_join_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
ForeignPathcreate_foreign_upper_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
 
Relids calc_nestloop_required_outer (Relids outerrelids, Relids outer_paramrels, Relids innerrelids, Relids inner_paramrels)
 
Relids calc_non_nestloop_required_outer (Path *outer_path, Path *inner_path)
 
NestPathcreate_nestloop_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer)
 
MergePathcreate_mergejoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, List *restrict_clauses, List *pathkeys, Relids required_outer, List *mergeclauses, List *outersortkeys, List *innersortkeys, int outer_presorted_keys)
 
HashPathcreate_hashjoin_path (PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype, JoinCostWorkspace *workspace, JoinPathExtraData *extra, Path *outer_path, Path *inner_path, bool parallel_hash, List *restrict_clauses, Relids required_outer, List *hashclauses)
 
ProjectionPathcreate_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
Pathapply_projection_to_path (PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
 
ProjectSetPathcreate_set_projection_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
 
SortPathcreate_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
 
IncrementalSortPathcreate_incremental_sort_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
 
GroupPathcreate_group_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *groupClause, List *qual, double numGroups)
 
UniquePathcreate_unique_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
 
AggPathcreate_agg_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, AggStrategy aggstrategy, AggSplit aggsplit, List *groupClause, List *qual, const AggClauseCosts *aggcosts, double numGroups)
 
GroupingSetsPathcreate_groupingsets_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *having_qual, AggStrategy aggstrategy, List *rollups, const AggClauseCosts *agg_costs)
 
MinMaxAggPathcreate_minmaxagg_path (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *mmaggregates, List *quals)
 
WindowAggPathcreate_windowagg_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *windowFuncs, List *runCondition, WindowClause *winclause, List *qual, bool topwindow)
 
SetOpPathcreate_setop_path (PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, SetOpCmd cmd, SetOpStrategy strategy, List *groupList, double numGroups, double outputRows)
 
RecursiveUnionPathcreate_recursiveunion_path (PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
 
LockRowsPathcreate_lockrows_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *rowMarks, int epqParam)
 
ModifyTablePathcreate_modifytable_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, CmdType operation, bool canSetTag, Index nominalRelation, Index rootRelation, List *resultRelations, List *updateColnosLists, List *withCheckOptionLists, List *returningLists, List *rowMarks, OnConflictExpr *onconflict, List *mergeActionLists, List *mergeJoinConditions, int epqParam)
 
LimitPathcreate_limit_path (PlannerInfo *root, RelOptInfo *rel, Path *subpath, Node *limitOffset, Node *limitCount, LimitOption limitOption, int64 offset_est, int64 count_est)
 
void adjust_limit_rows_costs (double *rows, Cost *startup_cost, Cost *total_cost, int64 offset_est, int64 count_est)
 
Pathreparameterize_path (PlannerInfo *root, Path *path, Relids required_outer, double loop_count)
 
Pathreparameterize_path_by_child (PlannerInfo *root, Path *path, RelOptInfo *child_rel)
 
bool path_is_reparameterizable_by_child (Path *path, RelOptInfo *child_rel)
 
void setup_simple_rel_arrays (PlannerInfo *root)
 
void expand_planner_arrays (PlannerInfo *root, int add_size)
 
RelOptInfobuild_simple_rel (PlannerInfo *root, int relid, RelOptInfo *parent)
 
RelOptInfobuild_simple_grouped_rel (PlannerInfo *root, RelOptInfo *rel)
 
RelOptInfobuild_grouped_rel (PlannerInfo *root, RelOptInfo *rel)
 
RelOptInfofind_base_rel (PlannerInfo *root, int relid)
 
RelOptInfofind_base_rel_noerr (PlannerInfo *root, int relid)
 
RelOptInfofind_base_rel_ignore_join (PlannerInfo *root, int relid)
 
RelOptInfofind_join_rel (PlannerInfo *root, Relids relids)
 
RelOptInfobuild_join_rel (PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *pushed_down_joins, List **restrictlist_ptr)
 
Relids min_join_parameterization (PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
 
RelOptInfofetch_upper_rel (PlannerInfo *root, UpperRelationKind kind, Relids relids)
 
Relids find_childrel_parents (PlannerInfo *root, RelOptInfo *rel)
 
ParamPathInfoget_baserel_parampathinfo (PlannerInfo *root, RelOptInfo *baserel, Relids required_outer)
 
ParamPathInfoget_joinrel_parampathinfo (PlannerInfo *root, RelOptInfo *joinrel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, Relids required_outer, List **restrict_clauses)
 
ParamPathInfoget_appendrel_parampathinfo (RelOptInfo *appendrel, Relids required_outer)
 
ParamPathInfofind_param_path_info (RelOptInfo *rel, Relids required_outer)
 
Bitmapsetget_param_path_clause_serials (Path *path)
 
RelOptInfobuild_child_join_rel (PlannerInfo *root, RelOptInfo *outer_rel, RelOptInfo *inner_rel, RelOptInfo *parent_joinrel, List *restrictlist, SpecialJoinInfo *sjinfo, int nappinfos, AppendRelInfo **appinfos)
 
RelAggInfocreate_rel_agg_info (PlannerInfo *root, RelOptInfo *rel, bool calculate_grouped_rows)
 

Variables

PGDLLIMPORT joinrel_setup_hook_type joinrel_setup_hook
 

Typedef Documentation

◆ AppendPathInput

◆ 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 36 of file pathnode.h.

Function Documentation

◆ add_partial_path()

void add_partial_path ( RelOptInfo parent_rel,
Path new_path 
)
extern

Definition at line 794 of file pathnode.c.

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

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

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

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

◆ add_path()

void add_path ( RelOptInfo parent_rel,
Path new_path 
)
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:2001
#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 3801 of file pathnode.c.

3806{
3807 double input_rows = *rows;
3808 Cost input_startup_cost = *startup_cost;
3809 Cost input_total_cost = *total_cost;
3810
3811 if (offset_est != 0)
3812 {
3813 double offset_rows;
3814
3815 if (offset_est > 0)
3816 offset_rows = (double) offset_est;
3817 else
3819 if (offset_rows > *rows)
3820 offset_rows = *rows;
3821 if (input_rows > 0)
3822 *startup_cost +=
3825 *rows -= offset_rows;
3826 if (*rows < 1)
3827 *rows = 1;
3828 }
3829
3830 if (count_est != 0)
3831 {
3832 double count_rows;
3833
3834 if (count_est > 0)
3835 count_rows = (double) count_est;
3836 else
3838 if (count_rows > *rows)
3839 count_rows = *rows;
3840 if (input_rows > 0)
3841 *total_cost = *startup_cost +
3844 *rows = count_rows;
3845 if (*rows < 1)
3846 *rows = 1;
3847 }
3848}
double clamp_row_est(double nrows)
Definition costsize.c:213
double Cost
Definition nodes.h:261

References clamp_row_est(), and fb().

Referenced by create_limit_path(), and estimate_path_cost_size().

◆ apply_projection_to_path()

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

Definition at line 2649 of file pathnode.c.

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

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

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

◆ 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:629
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:5570
void add_child_join_rel_equivalences(PlannerInfo *root, int nappinfos, AppendRelInfo **appinfos, RelOptInfo *parent_joinrel, RelOptInfo *child_joinrel)
#define makeNode(_type_)
Definition nodes.h:161
@ RTE_JOIN
bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel)
Definition pathkeys.c:2291
Bitmapset * Relids
Definition pathnodes.h:103
@ RELOPT_OTHER_JOINREL
Definition pathnodes.h:968
#define IS_OTHER_REL(rel)
Definition pathnodes.h:992
#define InvalidOid
static void build_joinrel_partition_info(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition relnode.c: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:1130
bool consider_param_startup
Definition pathnodes.h:1023
List * subplan_params
Definition pathnodes.h:1089
List * ppilist
Definition pathnodes.h:1039
bool useridiscurrent
Definition pathnodes.h:1103
uint32 amflags
Definition pathnodes.h:1093
List * joininfo
Definition pathnodes.h:1136
Bitmapset * notnullattnums
Definition pathnodes.h:1071
List * partition_qual
Definition pathnodes.h:1180
Relids relids
Definition pathnodes.h:1009
struct PathTarget * reltarget
Definition pathnodes.h:1033
Index relid
Definition pathnodes.h:1057
List * lateral_vars
Definition pathnodes.h:1075
struct RelAggInfo * agg_info
Definition pathnodes.h:1150
uint64 pgs_mask
Definition pathnodes.h:1027
List * unique_pathkeys
Definition pathnodes.h:1122
Cardinality tuples
Definition pathnodes.h:1084
bool consider_parallel
Definition pathnodes.h:1025
Relids top_parent_relids
Definition pathnodes.h:1162
bool partbounds_merged
Definition pathnodes.h:1178
BlockNumber pages
Definition pathnodes.h:1083
Relids lateral_relids
Definition pathnodes.h:1052
List * cheapest_parameterized_paths
Definition pathnodes.h:1043
List * pathlist
Definition pathnodes.h:1038
RelOptKind reloptkind
Definition pathnodes.h:1003
List * indexlist
Definition pathnodes.h:1079
Relids lateral_referencers
Definition pathnodes.h:1077
struct Path * cheapest_startup_path
Definition pathnodes.h:1041
QualCost baserestrictcost
Definition pathnodes.h:1132
struct Path * cheapest_total_path
Definition pathnodes.h:1042
List * unique_groupclause
Definition pathnodes.h:1124
struct RelOptInfo * grouped_rel
Definition pathnodes.h:1152
Bitmapset * eclass_indexes
Definition pathnodes.h:1087
Relids all_partrels
Definition pathnodes.h:1194
Relids direct_lateral_relids
Definition pathnodes.h:1050
bool has_eclass_joins
Definition pathnodes.h:1138
bool consider_startup
Definition pathnodes.h:1021
Bitmapset * live_parts
Definition pathnodes.h:1192
bool consider_partitionwise_join
Definition pathnodes.h:1144
List * partial_pathlist
Definition pathnodes.h:1040
PlannerInfo * subroot
Definition pathnodes.h:1088
AttrNumber max_attr
Definition pathnodes.h:1065
Relids nulling_relids
Definition pathnodes.h:1073
double allvisfrac
Definition pathnodes.h:1085
struct RelOptInfo * unique_rel
Definition pathnodes.h:1120
Cardinality rows
Definition pathnodes.h:1015
AttrNumber min_attr
Definition pathnodes.h:1063
RTEKind rtekind
Definition pathnodes.h:1061
PathTarget * create_empty_pathtarget(void)
Definition tlist.c:690

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

Referenced by try_partitionwise_join().

◆ build_grouped_rel()

RelOptInfo * build_grouped_rel ( PlannerInfo root,
RelOptInfo rel 
)
extern

Definition at line 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:1145
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:744
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:251
bool has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
List * lappend(List *list, void *datum)
Definition list.c:339
@ JOIN_FULL
Definition nodes.h:305
@ JOIN_INNER
Definition nodes.h:303
@ RELOPT_JOINREL
Definition pathnodes.h:966
void add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel, SpecialJoinInfo *sjinfo, List *pushed_down_joins, bool can_null)
Definition relnode.c: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:1081
List * unique_for_rels
Definition pathnodes.h:1112
List * non_unique_for_rels
Definition pathnodes.h:1114
int rel_parallel_workers
Definition pathnodes.h:1091
Index baserestrict_min_security
Definition pathnodes.h:1134
JoinType jointype
Definition pathnodes.h:3215

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:2285
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:1290
bool agg_useful
Definition pathnodes.h:1296
Cardinality grouped_rows
Definition pathnodes.h:1293
struct PathTarget * target
Definition pathnodes.h:1279

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

Referenced by setup_simple_grouped_rels().

◆ build_simple_rel()

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

Definition at line 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:554
#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:965
@ RELOPT_OTHER_MEMBER_REL
Definition pathnodes.h:967
static int list_length(const List *l)
Definition pg_list.h:152
void get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, RelOptInfo *rel)
Definition plancat.c: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 2230 of file pathnode.c.

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

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

Referenced by try_nestloop_path().

◆ calc_non_nestloop_required_outer()

Relids calc_non_nestloop_required_outer ( Path outer_path,
Path inner_path 
)
extern

Definition at line 2257 of file pathnode.c.

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

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

Referenced by try_hashjoin_path(), and try_mergejoin_path().

◆ compare_fractional_path_costs()

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

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

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

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

◆ create_append_path()

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

Definition at line 1305 of file pathnode.c.

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

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

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

◆ create_bitmap_and_path()

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

Definition at line 1135 of file pathnode.c.

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

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

Referenced by bitmap_and_cost_est(), and choose_bitmap_and().

◆ create_bitmap_heap_path()

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

Definition at line 1102 of file pathnode.c.

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

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

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

◆ create_bitmap_or_path()

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

Definition at line 1187 of file pathnode.c.

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

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

Referenced by generate_bitmap_or_paths().

◆ create_ctescan_path()

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

Definition at line 1970 of file pathnode.c.

1972{
1974
1975 pathnode->pathtype = T_CteScan;
1976 pathnode->parent = rel;
1977 pathnode->pathtarget = rel->reltarget;
1978 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1980 pathnode->parallel_aware = false;
1981 pathnode->parallel_safe = rel->consider_parallel;
1982 pathnode->parallel_workers = 0;
1983 pathnode->pathkeys = pathkeys;
1984
1985 cost_ctescan(pathnode, root, rel, pathnode->param_info);
1986
1987 return pathnode;
1988}
void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1744

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

Referenced by set_cte_pathlist().

◆ create_foreign_join_path()

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

Definition at line 2129 of file pathnode.c.

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

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

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

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

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

◆ create_foreignscan_path()

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

Definition at line 2081 of file pathnode.c.

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

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

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

◆ create_functionscan_path()

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

Definition at line 1892 of file pathnode.c.

1894{
1896
1897 pathnode->pathtype = T_FunctionScan;
1898 pathnode->parent = rel;
1899 pathnode->pathtarget = rel->reltarget;
1900 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1902 pathnode->parallel_aware = false;
1903 pathnode->parallel_safe = rel->consider_parallel;
1904 pathnode->parallel_workers = 0;
1905 pathnode->pathkeys = pathkeys;
1906
1907 cost_functionscan(pathnode, root, rel, pathnode->param_info);
1908
1909 return pathnode;
1910}
void cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1562

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

Referenced by set_function_pathlist().

◆ create_gather_merge_path()

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

Definition at line 1766 of file pathnode.c.

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

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

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

◆ create_gather_path()

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

Definition at line 1818 of file pathnode.c.

1820{
1822
1823 Assert(subpath->parallel_safe);
1824
1825 pathnode->path.pathtype = T_Gather;
1826 pathnode->path.parent = rel;
1827 pathnode->path.pathtarget = target;
1828 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1830 pathnode->path.parallel_aware = false;
1831 pathnode->path.parallel_safe = false;
1832 pathnode->path.parallel_workers = 0;
1833 pathnode->path.pathkeys = NIL; /* Gather has unordered result */
1834
1835 pathnode->subpath = subpath;
1836 pathnode->num_workers = subpath->parallel_workers;
1837 pathnode->single_copy = false;
1838
1839 if (pathnode->num_workers == 0)
1840 {
1841 pathnode->path.pathkeys = subpath->pathkeys;
1842 pathnode->num_workers = 1;
1843 pathnode->single_copy = true;
1844 }
1845
1846 cost_gather(pathnode, root, rel, pathnode->path.param_info, rows);
1847
1848 return pathnode;
1849}
void cost_gather(GatherPath *path, PlannerInfo *root, RelOptInfo *rel, ParamPathInfo *param_info, double *rows)
Definition costsize.c:429

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

Referenced by generate_gather_paths(), and generate_union_paths().

◆ create_group_path()

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

Definition at line 2901 of file pathnode.c.

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

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

Referenced by add_paths_to_grouping_rel(), and create_partial_grouping_paths().

◆ create_group_result_path()

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

Definition at line 1617 of file pathnode.c.

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

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

Referenced by create_degenerate_grouping_paths(), and query_planner().

◆ create_groupingsets_path()

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

Definition at line 3092 of file pathnode.c.

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

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

Referenced by consider_groupingsets_paths().

◆ create_hashjoin_path()

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

Definition at line 2474 of file pathnode.c.

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

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

Referenced by try_hashjoin_path(), and try_partial_hashjoin_path().

◆ create_incremental_sort_path()

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

Definition at line 2808 of file pathnode.c.

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

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

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

◆ create_index_path()

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

Definition at line 1053 of file pathnode.c.

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

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

Referenced by build_index_paths(), and plan_cluster_use_sort().

◆ create_limit_path()

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

Definition at line 3745 of file pathnode.c.

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

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

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

◆ create_lockrows_path()

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

Definition at line 3583 of file pathnode.c.

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

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

1666{
1668
1669 Assert(subpath->parent == rel);
1670
1671 pathnode->path.pathtype = T_Material;
1672 pathnode->path.parent = rel;
1673 pathnode->path.pathtarget = rel->reltarget;
1674 pathnode->path.param_info = subpath->param_info;
1675 pathnode->path.parallel_aware = false;
1676 pathnode->path.parallel_safe = rel->consider_parallel &&
1677 subpath->parallel_safe;
1678 pathnode->path.parallel_workers = subpath->parallel_workers;
1679 pathnode->path.pathkeys = subpath->pathkeys;
1680
1681 pathnode->subpath = subpath;
1682
1683 cost_material(&pathnode->path,
1684 enabled,
1685 subpath->disabled_nodes,
1686 subpath->startup_cost,
1687 subpath->total_cost,
1688 subpath->rows,
1689 subpath->pathtarget->width);
1690
1691 return pathnode;
1692}
void cost_material(Path *path, bool enabled, int input_disabled_nodes, Cost input_startup_cost, Cost input_total_cost, double tuples, int width)
Definition costsize.c:2582

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

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

◆ create_memoize_path()

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

Definition at line 1699 of file pathnode.c.

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

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

Referenced by get_memoize_path(), and reparameterize_path().

◆ create_merge_append_path()

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

Definition at line 1477 of file pathnode.c.

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

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

Referenced by generate_orderedappend_paths(), and generate_union_paths().

◆ create_mergejoin_path()

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

Definition at line 2406 of file pathnode.c.

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

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

Referenced by try_mergejoin_path(), and try_partial_mergejoin_path().

◆ create_minmaxagg_path()

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

Definition at line 3255 of file pathnode.c.

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

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

Referenced by preprocess_minmax_aggregates().

◆ create_modifytable_path()

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

Definition at line 3645 of file pathnode.c.

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

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

Referenced by grouping_planner().

◆ create_namedtuplestorescan_path()

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

Definition at line 1996 of file pathnode.c.

1998{
2000
2001 pathnode->pathtype = T_NamedTuplestoreScan;
2002 pathnode->parent = rel;
2003 pathnode->pathtarget = rel->reltarget;
2004 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2006 pathnode->parallel_aware = false;
2007 pathnode->parallel_safe = rel->consider_parallel;
2008 pathnode->parallel_workers = 0;
2009 pathnode->pathkeys = NIL; /* result is always unordered */
2010
2011 cost_namedtuplestorescan(pathnode, root, rel, pathnode->param_info);
2012
2013 return pathnode;
2014}
void cost_namedtuplestorescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1790

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

Referenced by set_namedtuplestore_pathlist().

◆ create_nestloop_path()

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

Definition at line 2309 of file pathnode.c.

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

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

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

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

◆ create_recursiveunion_path()

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

Definition at line 3538 of file pathnode.c.

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

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

Referenced by generate_recursion_path().

◆ create_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:596
PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
Definition costsize.c:6509
#define copyObject(obj)
Definition nodes.h:232
@ AGGSPLIT_INITIAL_SERIAL
Definition nodes.h:389
#define IS_GROUPED_REL(rel)
Definition pathnodes.h:1245
#define lfirst_node(type, lc)
Definition pg_list.h:176
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition planner.c:5818
static bool init_grouping_targets(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, PathTarget *agg_input, List **group_clauses, List **group_exprs)
Definition relnode.c: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:1287
List * group_clauses
Definition pathnodes.h:1285
struct PathTarget * agg_input
Definition pathnodes.h:1282
void add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
Definition tlist.c:704

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

Referenced by build_simple_grouped_rel(), and make_grouped_join_rel().

◆ create_resultscan_path()

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

Definition at line 2022 of file pathnode.c.

2024{
2026
2027 pathnode->pathtype = T_Result;
2028 pathnode->parent = rel;
2029 pathnode->pathtarget = rel->reltarget;
2030 pathnode->param_info = get_baserel_parampathinfo(root, rel,
2032 pathnode->parallel_aware = false;
2033 pathnode->parallel_safe = rel->consider_parallel;
2034 pathnode->parallel_workers = 0;
2035 pathnode->pathkeys = NIL; /* result is always unordered */
2036
2037 cost_resultscan(pathnode, root, rel, pathnode->param_info);
2038
2039 return pathnode;
2040}
void cost_resultscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1832

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

Referenced by reparameterize_path(), and set_result_pathlist().

◆ create_samplescan_path()

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

Definition at line 1012 of file pathnode.c.

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

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

Referenced by reparameterize_path(), and set_tablesample_rel_pathlist().

◆ create_seqscan_path()

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

Definition at line 987 of file pathnode.c.

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

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

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

◆ create_set_projection_path()

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

Definition at line 2738 of file pathnode.c.

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

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

Referenced by adjust_paths_for_srfs().

◆ create_setop_path()

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

Definition at line 3419 of file pathnode.c.

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

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

Referenced by generate_nonunion_paths().

◆ create_sort_path()

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

Definition at line 2857 of file pathnode.c.

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

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

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

◆ create_subqueryscan_path()

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

Definition at line 1862 of file pathnode.c.

1865{
1867
1868 pathnode->path.pathtype = T_SubqueryScan;
1869 pathnode->path.parent = rel;
1870 pathnode->path.pathtarget = rel->reltarget;
1871 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
1873 pathnode->path.parallel_aware = false;
1874 pathnode->path.parallel_safe = rel->consider_parallel &&
1875 subpath->parallel_safe;
1876 pathnode->path.parallel_workers = subpath->parallel_workers;
1877 pathnode->path.pathkeys = pathkeys;
1878 pathnode->subpath = subpath;
1879
1880 cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
1882
1883 return pathnode;
1884}
void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info, bool trivial_pathtarget)
Definition costsize.c:1477

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

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

◆ create_tablefuncscan_path()

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

Definition at line 1918 of file pathnode.c.

1920{
1922
1923 pathnode->pathtype = T_TableFuncScan;
1924 pathnode->parent = rel;
1925 pathnode->pathtarget = rel->reltarget;
1926 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1928 pathnode->parallel_aware = false;
1929 pathnode->parallel_safe = rel->consider_parallel;
1930 pathnode->parallel_workers = 0;
1931 pathnode->pathkeys = NIL; /* result is always unordered */
1932
1933 cost_tablefuncscan(pathnode, root, rel, pathnode->param_info);
1934
1935 return pathnode;
1936}
void cost_tablefuncscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1628

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

Referenced by set_tablefunc_pathlist().

◆ create_tidrangescan_path()

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

Definition at line 1268 of file pathnode.c.

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

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

Referenced by create_tidscan_paths().

◆ create_tidscan_path()

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

Definition at line 1239 of file pathnode.c.

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

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

Referenced by BuildParameterizedTidPaths(), and create_tidscan_paths().

◆ create_unique_path()

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

Definition at line 2958 of file pathnode.c.

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

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

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

◆ create_valuesscan_path()

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

Definition at line 1944 of file pathnode.c.

1946{
1948
1949 pathnode->pathtype = T_ValuesScan;
1950 pathnode->parent = rel;
1951 pathnode->pathtarget = rel->reltarget;
1952 pathnode->param_info = get_baserel_parampathinfo(root, rel,
1954 pathnode->parallel_aware = false;
1955 pathnode->parallel_safe = rel->consider_parallel;
1956 pathnode->parallel_workers = 0;
1957 pathnode->pathkeys = NIL; /* result is always unordered */
1958
1959 cost_valuesscan(pathnode, root, rel, pathnode->param_info);
1960
1961 return pathnode;
1962}
void cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info)
Definition costsize.c:1689

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

Referenced by set_values_pathlist().

◆ create_windowagg_path()

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

Definition at line 3346 of file pathnode.c.

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

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

Referenced by create_one_window_path().

◆ create_worktablescan_path()

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

Definition at line 2048 of file pathnode.c.

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

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

Referenced by set_worktable_pathlist().

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

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:969

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

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

◆ find_base_rel()

◆ find_base_rel_ignore_join()

RelOptInfo * find_base_rel_ignore_join ( PlannerInfo root,
int  relid 
)
extern

Definition at line 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:799
unsigned int Index
Definition c.h:640
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition relnode.c:533
Index parent_relid
Definition pathnodes.h:3286

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:5521
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:5602
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:1093
static ListCell * list_head(const List *l)
Definition pg_list.h:128
Path * outerjoinpath
Definition pathnodes.h:2390
Path * innerjoinpath
Definition pathnodes.h:2391
List * joinrestrictinfo
Definition pathnodes.h:2393

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

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

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

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

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

Referenced by get_cheapest_parameterized_child_path(), and reparameterize_path().

◆ reparameterize_path_by_child()

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

Definition at line 4039 of file pathnode.c.

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

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

Referenced by create_nestloop_plan(), and reparameterize_pathlist_by_child().

◆ set_cheapest()

void set_cheapest ( RelOptInfo parent_rel)
extern

Definition at line 268 of file pathnode.c.

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

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

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

◆ setup_simple_rel_arrays()

void setup_simple_rel_arrays ( PlannerInfo root)
extern

Definition at line 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().