PostgreSQL Source Code git master
relnode.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/nbtree.h"
#include "catalog/pg_constraint.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/appendinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/inherit.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/placeholder.h"
#include "optimizer/plancat.h"
#include "optimizer/planner.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteManip.h"
#include "utils/hsearch.h"
#include "utils/lsyscache.h"
#include "utils/selfuncs.h"
#include "utils/typcache.h"
Include dependency graph for relnode.c:

Go to the source code of this file.

Data Structures

struct  JoinHashEntry
 

Typedefs

typedef struct JoinHashEntry JoinHashEntry
 

Functions

static void build_joinrel_tlist (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel, SpecialJoinInfo *sjinfo, List *pushed_down_joins, bool can_null)
 
static Listbuild_joinrel_restrictlist (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
 
static void build_joinrel_joinlist (RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
 
static Listsubbuild_joinrel_restrictlist (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel, Relids both_input_relids, List *new_restrictlist)
 
static Listsubbuild_joinrel_joinlist (RelOptInfo *joinrel, List *joininfo_list, List *new_joininfo)
 
static void set_foreign_rel_properties (RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
 
static void add_join_rel (PlannerInfo *root, RelOptInfo *joinrel)
 
static void build_joinrel_partition_info (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
 
static bool have_partkey_equi_join (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *rel1, RelOptInfo *rel2, JoinType jointype, List *restrictlist)
 
static int match_expr_to_partition_keys (Expr *expr, RelOptInfo *rel, bool strict_op)
 
static void set_joinrel_partition_key_exprs (RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype)
 
static void build_child_join_reltarget (PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, int nappinfos, AppendRelInfo **appinfos)
 
static bool eager_aggregation_possible_for_relation (PlannerInfo *root, RelOptInfo *rel)
 
static bool init_grouping_targets (PlannerInfo *root, RelOptInfo *rel, PathTarget *target, PathTarget *agg_input, List **group_clauses, List **group_exprs)
 
static bool is_var_in_aggref_only (PlannerInfo *root, Var *var)
 
static bool is_var_needed_by_join (PlannerInfo *root, Var *var, RelOptInfo *rel)
 
static Index get_expression_sortgroupref (PlannerInfo *root, Expr *expr)
 
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)
 
static void build_join_rel_hash (PlannerInfo *root)
 
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)
 
RelOptInfobuild_child_join_rel (PlannerInfo *root, RelOptInfo *outer_rel, RelOptInfo *inner_rel, RelOptInfo *parent_joinrel, List *restrictlist, SpecialJoinInfo *sjinfo, int nappinfos, AppendRelInfo **appinfos)
 
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)
 
RelAggInfocreate_rel_agg_info (PlannerInfo *root, RelOptInfo *rel, bool calculate_grouped_rows)
 

Typedef Documentation

◆ JoinHashEntry

typedef struct JoinHashEntry JoinHashEntry

Function Documentation

◆ add_join_rel()

static void add_join_rel ( PlannerInfo root,
RelOptInfo joinrel 
)
static

Definition at line 742 of file relnode.c.

743{
744 /* GEQO requires us to append the new joinrel to the end of the list! */
745 root->join_rel_list = lappend(root->join_rel_list, joinrel);
746
747 /* store it into the auxiliary hashtable if there is one. */
748 if (root->join_rel_hash)
749 {
750 JoinHashEntry *hentry;
751 bool found;
752
753 hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
754 &(joinrel->relids),
756 &found);
757 Assert(!found);
758 hentry->join_rel = joinrel;
759 }
760}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
Assert(PointerIsAligned(start, uint64))
@ HASH_ENTER
Definition: hsearch.h:114
List * lappend(List *list, void *datum)
Definition: list.c:339
tree ctl root
Definition: radixtree.h:1857
RelOptInfo * join_rel
Definition: relnode.c:47
Relids relids
Definition: pathnodes.h:927

References Assert(), HASH_ENTER, hash_search(), JoinHashEntry::join_rel, lappend(), RelOptInfo::relids, and root.

Referenced by build_child_join_rel(), and build_join_rel().

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

Definition at line 1001 of file relnode.c.

1005{
1006 RelOptInfo *joinrel = makeNode(RelOptInfo);
1007
1008 /* Only joins between "other" relations land here. */
1009 Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
1010
1011 /* The parent joinrel should have consider_partitionwise_join set. */
1012 Assert(parent_joinrel->consider_partitionwise_join);
1013
1015 joinrel->relids = adjust_child_relids(parent_joinrel->relids,
1016 nappinfos, appinfos);
1017 joinrel->rows = 0;
1018 /* cheap startup cost is interesting iff not all tuples to be retrieved */
1019 joinrel->consider_startup = (root->tuple_fraction > 0);
1020 joinrel->consider_param_startup = false;
1021 joinrel->consider_parallel = false;
1023 joinrel->pathlist = NIL;
1024 joinrel->ppilist = NIL;
1025 joinrel->partial_pathlist = NIL;
1026 joinrel->cheapest_startup_path = NULL;
1027 joinrel->cheapest_total_path = NULL;
1029 joinrel->direct_lateral_relids = NULL;
1030 joinrel->lateral_relids = NULL;
1031 joinrel->relid = 0; /* indicates not a baserel */
1032 joinrel->rtekind = RTE_JOIN;
1033 joinrel->min_attr = 0;
1034 joinrel->max_attr = 0;
1035 joinrel->attr_needed = NULL;
1036 joinrel->attr_widths = NULL;
1037 joinrel->notnullattnums = NULL;
1038 joinrel->nulling_relids = NULL;
1039 joinrel->lateral_vars = NIL;
1040 joinrel->lateral_referencers = NULL;
1041 joinrel->indexlist = NIL;
1042 joinrel->pages = 0;
1043 joinrel->tuples = 0;
1044 joinrel->allvisfrac = 0;
1045 joinrel->eclass_indexes = NULL;
1046 joinrel->subroot = NULL;
1047 joinrel->subplan_params = NIL;
1048 joinrel->amflags = 0;
1049 joinrel->serverid = InvalidOid;
1050 joinrel->userid = InvalidOid;
1051 joinrel->useridiscurrent = false;
1052 joinrel->fdwroutine = NULL;
1053 joinrel->fdw_private = NULL;
1054 joinrel->unique_rel = NULL;
1055 joinrel->unique_pathkeys = NIL;
1056 joinrel->unique_groupclause = NIL;
1057 joinrel->baserestrictinfo = NIL;
1058 joinrel->baserestrictcost.startup = 0;
1059 joinrel->baserestrictcost.per_tuple = 0;
1060 joinrel->joininfo = NIL;
1061 joinrel->has_eclass_joins = false;
1062 joinrel->consider_partitionwise_join = false; /* might get changed later */
1063 joinrel->agg_info = NULL;
1064 joinrel->grouped_rel = NULL;
1065 joinrel->parent = parent_joinrel;
1066 joinrel->top_parent = parent_joinrel->top_parent ? parent_joinrel->top_parent : parent_joinrel;
1067 joinrel->top_parent_relids = joinrel->top_parent->relids;
1068 joinrel->part_scheme = NULL;
1069 joinrel->nparts = -1;
1070 joinrel->boundinfo = NULL;
1071 joinrel->partbounds_merged = false;
1072 joinrel->partition_qual = NIL;
1073 joinrel->part_rels = NULL;
1074 joinrel->live_parts = NULL;
1075 joinrel->all_partrels = NULL;
1076 joinrel->partexprs = NULL;
1077 joinrel->nullable_partexprs = NULL;
1078
1079 /* Compute information relevant to foreign relations. */
1080 set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
1081
1082 /* Set up reltarget struct */
1083 build_child_join_reltarget(root, parent_joinrel, joinrel,
1084 nappinfos, appinfos);
1085
1086 /* Construct joininfo list. */
1088 (Node *) parent_joinrel->joininfo,
1089 nappinfos,
1090 appinfos);
1091
1092 /*
1093 * Lateral relids referred in child join will be same as that referred in
1094 * the parent relation.
1095 */
1096 joinrel->direct_lateral_relids = (Relids) bms_copy(parent_joinrel->direct_lateral_relids);
1097 joinrel->lateral_relids = (Relids) bms_copy(parent_joinrel->lateral_relids);
1098
1099 /*
1100 * If the parent joinrel has pending equivalence classes, so does the
1101 * child.
1102 */
1103 joinrel->has_eclass_joins = parent_joinrel->has_eclass_joins;
1104
1105 /* Is the join between partitions itself partitioned? */
1106 build_joinrel_partition_info(root, joinrel, outer_rel, inner_rel, sjinfo,
1107 restrictlist);
1108
1109 /* Child joinrel is parallel safe if parent is parallel safe. */
1110 joinrel->consider_parallel = parent_joinrel->consider_parallel;
1111
1112 /* Set estimates of the child-joinrel's size. */
1113 set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
1114 sjinfo, restrictlist);
1115
1116 /* We build the join only once. */
1117 Assert(!find_join_rel(root, joinrel->relids));
1118
1119 /* Add the relation to the PlannerInfo. */
1120 add_join_rel(root, joinrel);
1121
1122 /*
1123 * We might need EquivalenceClass members corresponding to the child join,
1124 * so that we can represent sort pathkeys for it. As with children of
1125 * baserels, we shouldn't need this unless there are relevant eclass joins
1126 * (implying that a merge join might be possible) or pathkeys to sort by.
1127 */
1128 if (joinrel->has_eclass_joins || has_useful_pathkeys(root, parent_joinrel))
1130 nappinfos, appinfos,
1131 parent_joinrel, joinrel);
1132
1133 return joinrel;
1134}
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:200
Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:625
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition: costsize.c:5453
void add_child_join_rel_equivalences(PlannerInfo *root, int nappinfos, AppendRelInfo **appinfos, RelOptInfo *parent_joinrel, RelOptInfo *child_joinrel)
Definition: equivclass.c:2941
#define makeNode(_type_)
Definition: nodes.h:161
@ RTE_JOIN
Definition: parsenodes.h:1045
bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel)
Definition: pathkeys.c:2291
Bitmapset * Relids
Definition: pathnodes.h:30
@ RELOPT_OTHER_JOINREL
Definition: pathnodes.h:886
#define IS_OTHER_REL(rel)
Definition: pathnodes.h:910
#define NIL
Definition: pg_list.h:68
#define InvalidOid
Definition: postgres_ext.h:37
static void build_joinrel_partition_info(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition: relnode.c:2113
RelOptInfo * find_join_rel(PlannerInfo *root, Relids relids)
Definition: relnode.c:642
static void build_child_join_reltarget(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, int nappinfos, AppendRelInfo **appinfos)
Definition: relnode.c:2626
static void set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:704
static void add_join_rel(PlannerInfo *root, RelOptInfo *joinrel)
Definition: relnode.c:742
Definition: pg_list.h:54
Definition: nodes.h:135
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
List * baserestrictinfo
Definition: pathnodes.h:1046
bool consider_param_startup
Definition: pathnodes.h:941
List * subplan_params
Definition: pathnodes.h:1005
List * ppilist
Definition: pathnodes.h:955
bool useridiscurrent
Definition: pathnodes.h:1019
uint32 amflags
Definition: pathnodes.h:1009
List * joininfo
Definition: pathnodes.h:1052
Bitmapset * notnullattnums
Definition: pathnodes.h:987
List * partition_qual
Definition: pathnodes.h:1096
struct PathTarget * reltarget
Definition: pathnodes.h:949
Index relid
Definition: pathnodes.h:973
List * lateral_vars
Definition: pathnodes.h:991
struct RelAggInfo * agg_info
Definition: pathnodes.h:1066
List * unique_pathkeys
Definition: pathnodes.h:1038
Cardinality tuples
Definition: pathnodes.h:1000
bool consider_parallel
Definition: pathnodes.h:943
Relids top_parent_relids
Definition: pathnodes.h:1078
bool partbounds_merged
Definition: pathnodes.h:1094
BlockNumber pages
Definition: pathnodes.h:999
Relids lateral_relids
Definition: pathnodes.h:968
List * cheapest_parameterized_paths
Definition: pathnodes.h:959
List * pathlist
Definition: pathnodes.h:954
RelOptKind reloptkind
Definition: pathnodes.h:921
List * indexlist
Definition: pathnodes.h:995
Relids lateral_referencers
Definition: pathnodes.h:993
struct Path * cheapest_startup_path
Definition: pathnodes.h:957
QualCost baserestrictcost
Definition: pathnodes.h:1048
struct Path * cheapest_total_path
Definition: pathnodes.h:958
List * unique_groupclause
Definition: pathnodes.h:1040
struct RelOptInfo * grouped_rel
Definition: pathnodes.h:1068
Bitmapset * eclass_indexes
Definition: pathnodes.h:1003
Relids all_partrels
Definition: pathnodes.h:1110
Relids direct_lateral_relids
Definition: pathnodes.h:966
bool has_eclass_joins
Definition: pathnodes.h:1054
Oid serverid
Definition: pathnodes.h:1015
bool consider_startup
Definition: pathnodes.h:939
Bitmapset * live_parts
Definition: pathnodes.h:1108
bool consider_partitionwise_join
Definition: pathnodes.h:1060
List * partial_pathlist
Definition: pathnodes.h:956
PlannerInfo * subroot
Definition: pathnodes.h:1004
AttrNumber max_attr
Definition: pathnodes.h:981
Relids nulling_relids
Definition: pathnodes.h:989
double allvisfrac
Definition: pathnodes.h:1001
struct RelOptInfo * unique_rel
Definition: pathnodes.h:1036
Cardinality rows
Definition: pathnodes.h:933
AttrNumber min_attr
Definition: pathnodes.h:979
RTEKind rtekind
Definition: pathnodes.h:977
PathTarget * create_empty_pathtarget(void)
Definition: tlist.c:681

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, find_join_rel(), RelOptInfo::grouped_rel, RelOptInfo::has_eclass_joins, has_useful_pathkeys(), RelOptInfo::indexlist, InvalidOid, IS_OTHER_REL, RelOptInfo::joininfo, 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::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_child_join_reltarget()

static void build_child_join_reltarget ( PlannerInfo root,
RelOptInfo parentrel,
RelOptInfo childrel,
int  nappinfos,
AppendRelInfo **  appinfos 
)
static

Definition at line 2626 of file relnode.c.

2631{
2632 /* Build the targetlist */
2633 childrel->reltarget->exprs = (List *)
2635 (Node *) parentrel->reltarget->exprs,
2636 nappinfos, appinfos);
2637
2638 /* Set the cost and width fields */
2639 childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
2640 childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
2641 childrel->reltarget->width = parentrel->reltarget->width;
2642}
List * exprs
Definition: pathnodes.h:1780
QualCost cost
Definition: pathnodes.h:1786

References adjust_appendrel_attrs(), PathTarget::cost, PathTarget::exprs, QualCost::per_tuple, RelOptInfo::reltarget, root, QualCost::startup, and PathTarget::width.

Referenced by build_child_join_rel().

◆ build_grouped_rel()

RelOptInfo * build_grouped_rel ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 484 of file relnode.c.

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

References RelOptInfo::all_partrels, RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::consider_partitionwise_join, 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 
)

Definition at line 780 of file relnode.c.

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

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, 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, 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::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_join_rel_hash()

static void build_join_rel_hash ( PlannerInfo root)
static

Definition at line 601 of file relnode.c.

602{
603 HTAB *hashtab;
604 HASHCTL hash_ctl;
605 ListCell *l;
606
607 /* Create the hash table */
608 hash_ctl.keysize = sizeof(Relids);
609 hash_ctl.entrysize = sizeof(JoinHashEntry);
610 hash_ctl.hash = bitmap_hash;
611 hash_ctl.match = bitmap_match;
612 hash_ctl.hcxt = CurrentMemoryContext;
613 hashtab = hash_create("JoinRelHashTable",
614 256L,
615 &hash_ctl,
617
618 /* Insert all the already-existing joinrels */
619 foreach(l, root->join_rel_list)
620 {
621 RelOptInfo *rel = (RelOptInfo *) lfirst(l);
622 JoinHashEntry *hentry;
623 bool found;
624
625 hentry = (JoinHashEntry *) hash_search(hashtab,
626 &(rel->relids),
628 &found);
629 Assert(!found);
630 hentry->join_rel = rel;
631 }
632
633 root->join_rel_hash = hashtab;
634}
uint32 bitmap_hash(const void *key, Size keysize)
Definition: bitmapset.c:1433
int bitmap_match(const void *key1, const void *key2, Size keysize)
Definition: bitmapset.c:1443
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_COMPARE
Definition: hsearch.h:99
#define HASH_FUNCTION
Definition: hsearch.h:98
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
#define lfirst(lc)
Definition: pg_list.h:172
struct JoinHashEntry JoinHashEntry
Size keysize
Definition: hsearch.h:75
HashValueFunc hash
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:76
HashCompareFunc match
Definition: hsearch.h:80
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:222

References Assert(), bitmap_hash(), bitmap_match(), CurrentMemoryContext, HASHCTL::entrysize, HASHCTL::hash, HASH_COMPARE, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FUNCTION, hash_search(), HASHCTL::hcxt, JoinHashEntry::join_rel, HASHCTL::keysize, lfirst, HASHCTL::match, RelOptInfo::relids, and root.

Referenced by find_join_rel().

◆ build_joinrel_joinlist()

static void build_joinrel_joinlist ( RelOptInfo joinrel,
RelOptInfo outer_rel,
RelOptInfo inner_rel 
)
static

Definition at line 1445 of file relnode.c.

1448{
1449 List *result;
1450
1451 /*
1452 * Collect all the clauses that syntactically belong above this level,
1453 * eliminating any duplicates (important since we will see many of the
1454 * same clauses arriving from both input relations).
1455 */
1456 result = subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo, NIL);
1457 result = subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo, result);
1458
1459 joinrel->joininfo = result;
1460}
static List * subbuild_joinrel_joinlist(RelOptInfo *joinrel, List *joininfo_list, List *new_joininfo)
Definition: relnode.c:1529

References RelOptInfo::joininfo, NIL, and subbuild_joinrel_joinlist().

Referenced by build_join_rel().

◆ build_joinrel_partition_info()

static void build_joinrel_partition_info ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
SpecialJoinInfo sjinfo,
List restrictlist 
)
static

Definition at line 2113 of file relnode.c.

2117{
2118 PartitionScheme part_scheme;
2119
2120 /* Nothing to do if partitionwise join technique is disabled. */
2122 {
2123 Assert(!IS_PARTITIONED_REL(joinrel));
2124 return;
2125 }
2126
2127 /*
2128 * We can only consider this join as an input to further partitionwise
2129 * joins if (a) the input relations are partitioned and have
2130 * consider_partitionwise_join=true, (b) the partition schemes match, and
2131 * (c) we can identify an equi-join between the partition keys. Note that
2132 * if it were possible for have_partkey_equi_join to return different
2133 * answers for the same joinrel depending on which join ordering we try
2134 * first, this logic would break. That shouldn't happen, though, because
2135 * of the way the query planner deduces implied equalities and reorders
2136 * the joins. Please see optimizer/README for details.
2137 */
2138 if (outer_rel->part_scheme == NULL || inner_rel->part_scheme == NULL ||
2139 !outer_rel->consider_partitionwise_join ||
2140 !inner_rel->consider_partitionwise_join ||
2141 outer_rel->part_scheme != inner_rel->part_scheme ||
2142 !have_partkey_equi_join(root, joinrel, outer_rel, inner_rel,
2143 sjinfo->jointype, restrictlist))
2144 {
2145 Assert(!IS_PARTITIONED_REL(joinrel));
2146 return;
2147 }
2148
2149 part_scheme = outer_rel->part_scheme;
2150
2151 /*
2152 * This function will be called only once for each joinrel, hence it
2153 * should not have partitioning fields filled yet.
2154 */
2155 Assert(!joinrel->part_scheme && !joinrel->partexprs &&
2156 !joinrel->nullable_partexprs && !joinrel->part_rels &&
2157 !joinrel->boundinfo);
2158
2159 /*
2160 * If the join relation is partitioned, it uses the same partitioning
2161 * scheme as the joining relations.
2162 *
2163 * Note: we calculate the partition bounds, number of partitions, and
2164 * child-join relations of the join relation in try_partitionwise_join().
2165 */
2166 joinrel->part_scheme = part_scheme;
2167 set_joinrel_partition_key_exprs(joinrel, outer_rel, inner_rel,
2168 sjinfo->jointype);
2169
2170 /*
2171 * Set the consider_partitionwise_join flag.
2172 */
2175 joinrel->consider_partitionwise_join = true;
2176}
bool enable_partitionwise_join
Definition: costsize.c:159
#define IS_PARTITIONED_REL(rel)
Definition: pathnodes.h:1135
static void set_joinrel_partition_key_exprs(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype)
Definition: relnode.c:2482
static bool have_partkey_equi_join(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *rel1, RelOptInfo *rel2, JoinType jointype, List *restrictlist)
Definition: relnode.c:2186

References Assert(), RelOptInfo::consider_partitionwise_join, enable_partitionwise_join, have_partkey_equi_join(), IS_PARTITIONED_REL, SpecialJoinInfo::jointype, root, and set_joinrel_partition_key_exprs().

Referenced by build_child_join_rel(), and build_join_rel().

◆ build_joinrel_restrictlist()

static List * build_joinrel_restrictlist ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
SpecialJoinInfo sjinfo 
)
static

Definition at line 1408 of file relnode.c.

1413{
1414 List *result;
1415 Relids both_input_relids;
1416
1417 both_input_relids = bms_union(outer_rel->relids, inner_rel->relids);
1418
1419 /*
1420 * Collect all the clauses that syntactically belong at this level,
1421 * eliminating any duplicates (important since we will see many of the
1422 * same clauses arriving from both input relations).
1423 */
1424 result = subbuild_joinrel_restrictlist(root, joinrel, outer_rel,
1425 both_input_relids, NIL);
1426 result = subbuild_joinrel_restrictlist(root, joinrel, inner_rel,
1427 both_input_relids, result);
1428
1429 /*
1430 * Add on any clauses derived from EquivalenceClasses. These cannot be
1431 * redundant with the clauses in the joininfo lists, so don't bother
1432 * checking.
1433 */
1434 result = list_concat(result,
1436 joinrel->relids,
1437 outer_rel->relids,
1438 inner_rel,
1439 sjinfo));
1440
1441 return result;
1442}
List * generate_join_implied_equalities(PlannerInfo *root, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
Definition: equivclass.c:1550
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
static List * subbuild_joinrel_restrictlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel, Relids both_input_relids, List *new_restrictlist)
Definition: relnode.c:1463

References bms_union(), generate_join_implied_equalities(), list_concat(), NIL, RelOptInfo::relids, root, and subbuild_joinrel_restrictlist().

Referenced by build_join_rel().

◆ build_joinrel_tlist()

static void build_joinrel_tlist ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo input_rel,
SpecialJoinInfo sjinfo,
List pushed_down_joins,
bool  can_null 
)
static

Definition at line 1223 of file relnode.c.

1228{
1229 Relids relids = joinrel->relids;
1230 int64 tuple_width = joinrel->reltarget->width;
1231 ListCell *vars;
1232 ListCell *lc;
1233
1234 foreach(vars, input_rel->reltarget->exprs)
1235 {
1236 Var *var = (Var *) lfirst(vars);
1237
1238 /*
1239 * For a PlaceHolderVar, we have to look up the PlaceHolderInfo.
1240 */
1241 if (IsA(var, PlaceHolderVar))
1242 {
1243 PlaceHolderVar *phv = (PlaceHolderVar *) var;
1245
1246 /* Is it still needed above this joinrel? */
1247 if (bms_nonempty_difference(phinfo->ph_needed, relids))
1248 {
1249 /*
1250 * Yup, add it to the output. If this join potentially nulls
1251 * this input, we have to update the PHV's phnullingrels,
1252 * which means making a copy.
1253 */
1254 if (can_null)
1255 {
1256 phv = copyObject(phv);
1257 /* See comments above to understand this logic */
1258 if (sjinfo->ojrelid != 0 &&
1259 bms_is_member(sjinfo->ojrelid, relids) &&
1260 (bms_is_subset(phv->phrels, sjinfo->syn_righthand) ||
1261 (sjinfo->jointype == JOIN_FULL &&
1262 bms_is_subset(phv->phrels, sjinfo->syn_lefthand))))
1264 sjinfo->ojrelid);
1265 foreach(lc, pushed_down_joins)
1266 {
1267 SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
1268
1269 Assert(bms_is_member(othersj->ojrelid, relids));
1270 if (bms_is_subset(phv->phrels, othersj->syn_righthand))
1272 othersj->ojrelid);
1273 }
1274 phv->phnullingrels =
1277 relids));
1278 }
1279
1280 joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
1281 phv);
1282 /* Bubbling up the precomputed result has cost zero */
1283 tuple_width += phinfo->ph_width;
1284 }
1285 continue;
1286 }
1287
1288 /*
1289 * Otherwise, anything in a baserel or joinrel targetlist ought to be
1290 * a Var. (More general cases can only appear in appendrel child
1291 * rels, which will never be seen here.)
1292 */
1293 if (!IsA(var, Var))
1294 elog(ERROR, "unexpected node type in rel targetlist: %d",
1295 (int) nodeTag(var));
1296
1297 if (var->varno == ROWID_VAR)
1298 {
1299 /* UPDATE/DELETE/MERGE row identity vars are always needed */
1301 list_nth(root->row_identity_vars, var->varattno - 1);
1302
1303 /* Update reltarget width estimate from RowIdentityVarInfo */
1304 tuple_width += ridinfo->rowidwidth;
1305 }
1306 else
1307 {
1308 RelOptInfo *baserel;
1309 int ndx;
1310
1311 /* Get the Var's original base rel */
1312 baserel = find_base_rel(root, var->varno);
1313
1314 /* Is it still needed above this joinrel? */
1315 ndx = var->varattno - baserel->min_attr;
1316 if (!bms_nonempty_difference(baserel->attr_needed[ndx], relids))
1317 continue; /* nope, skip it */
1318
1319 /* Update reltarget width estimate from baserel's attr_widths */
1320 tuple_width += baserel->attr_widths[ndx];
1321 }
1322
1323 /*
1324 * Add the Var to the output. If this join potentially nulls this
1325 * input, we have to update the Var's varnullingrels, which means
1326 * making a copy. But note that we don't ever add nullingrel bits to
1327 * row identity Vars (cf. comments in setrefs.c).
1328 */
1329 if (can_null && var->varno != ROWID_VAR)
1330 {
1331 var = copyObject(var);
1332 /* See comments above to understand this logic */
1333 if (sjinfo->ojrelid != 0 &&
1334 bms_is_member(sjinfo->ojrelid, relids) &&
1335 (bms_is_member(var->varno, sjinfo->syn_righthand) ||
1336 (sjinfo->jointype == JOIN_FULL &&
1337 bms_is_member(var->varno, sjinfo->syn_lefthand))))
1338 var->varnullingrels = bms_add_member(var->varnullingrels,
1339 sjinfo->ojrelid);
1340 foreach(lc, pushed_down_joins)
1341 {
1342 SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
1343
1344 Assert(bms_is_member(othersj->ojrelid, relids));
1345 if (bms_is_member(var->varno, othersj->syn_righthand))
1346 var->varnullingrels = bms_add_member(var->varnullingrels,
1347 othersj->ojrelid);
1348 }
1349 var->varnullingrels =
1350 bms_join(var->varnullingrels,
1352 relids));
1353 }
1354
1355 joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
1356 var);
1357
1358 /* Vars have cost zero, so no need to adjust reltarget->cost */
1359 }
1360
1361 joinrel->reltarget->width = clamp_width_est(tuple_width);
1362}
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:292
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:814
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1229
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:640
int64_t int64
Definition: c.h:538
int32 clamp_width_est(int64 tuple_width)
Definition: costsize.c:242
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define copyObject(obj)
Definition: nodes.h:232
#define nodeTag(nodeptr)
Definition: nodes.h:139
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
Definition: placeholder.c:83
#define ROWID_VAR
Definition: primnodes.h:245
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:529
Relids ph_needed
Definition: pathnodes.h:3317
Relids phnullingrels
Definition: pathnodes.h:3019
Relids commute_above_r
Definition: pathnodes.h:3124
Relids syn_lefthand
Definition: pathnodes.h:3119
Relids syn_righthand
Definition: pathnodes.h:3120
Definition: primnodes.h:262
AttrNumber varattno
Definition: primnodes.h:274
int varno
Definition: primnodes.h:269
Definition: regcomp.c:282

References Assert(), bms_add_member(), bms_intersect(), bms_is_member(), bms_is_subset(), bms_join(), bms_nonempty_difference(), clamp_width_est(), SpecialJoinInfo::commute_above_r, copyObject, elog, ERROR, PathTarget::exprs, find_base_rel(), find_placeholder_info(), IsA, JOIN_FULL, SpecialJoinInfo::jointype, lappend(), lfirst, list_nth(), RelOptInfo::min_attr, nodeTag, SpecialJoinInfo::ojrelid, PlaceHolderInfo::ph_needed, PlaceHolderInfo::ph_width, PlaceHolderVar::phnullingrels, RelOptInfo::relids, RelOptInfo::reltarget, root, ROWID_VAR, RowIdentityVarInfo::rowidwidth, SpecialJoinInfo::syn_lefthand, SpecialJoinInfo::syn_righthand, Var::varattno, Var::varno, and PathTarget::width.

Referenced by build_join_rel().

◆ build_simple_grouped_rel()

RelOptInfo * build_simple_grouped_rel ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 433 of file relnode.c.

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

References RelOptInfo::agg_info, RelAggInfo::agg_useful, RelAggInfo::apply_agg_at, Assert(), bms_copy(), build_grouped_rel(), create_rel_agg_info(), 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 
)

Definition at line 206 of file relnode.c.

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

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, RTEPermissionInfo::checkAsUser, 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, get_relation_info(), getRTEPermissionInfo(), RelOptInfo::grouped_rel, RelOptInfo::has_eclass_joins, RelOptInfo::indexlist, RangeTblEntry::inh, 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(), RelOptInfo::partbounds_merged, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, 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, RangeTblEntry::rtekind, 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().

◆ create_rel_agg_info()

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

Definition at line 2655 of file relnode.c.

2657{
2658 ListCell *lc;
2659 RelAggInfo *result;
2660 PathTarget *agg_input;
2661 PathTarget *target;
2662 List *group_clauses = NIL;
2663 List *group_exprs = NIL;
2664
2665 /*
2666 * The lists of aggregate expressions and grouping expressions should have
2667 * been constructed.
2668 */
2669 Assert(root->agg_clause_list != NIL);
2670 Assert(root->group_expr_list != NIL);
2671
2672 /*
2673 * If this is a child rel, the grouped rel for its parent rel must have
2674 * been created if it can. So we can just use parent's RelAggInfo if
2675 * there is one, with appropriate variable substitutions.
2676 */
2677 if (IS_OTHER_REL(rel))
2678 {
2679 RelOptInfo *grouped_rel;
2680 RelAggInfo *agg_info;
2681
2682 grouped_rel = rel->top_parent->grouped_rel;
2683 if (grouped_rel == NULL)
2684 return NULL;
2685
2686 Assert(IS_GROUPED_REL(grouped_rel));
2687
2688 /* Must do multi-level transformation */
2689 agg_info = (RelAggInfo *)
2691 (Node *) grouped_rel->agg_info,
2692 rel,
2693 rel->top_parent);
2694
2695 agg_info->apply_agg_at = NULL; /* caller will change this later */
2696
2697 if (calculate_grouped_rows)
2698 {
2699 agg_info->grouped_rows =
2701 rel->rows, NULL, NULL);
2702
2703 /*
2704 * The grouped paths for the given relation are considered useful
2705 * iff the average group size is no less than
2706 * min_eager_agg_group_size.
2707 */
2708 agg_info->agg_useful =
2709 (rel->rows / agg_info->grouped_rows) >= min_eager_agg_group_size;
2710 }
2711
2712 return agg_info;
2713 }
2714
2715 /* Check if it's possible to produce grouped paths for this relation. */
2717 return NULL;
2718
2719 /*
2720 * Create targets for the grouped paths and for the input paths of the
2721 * grouped paths.
2722 */
2723 target = create_empty_pathtarget();
2724 agg_input = create_empty_pathtarget();
2725
2726 /* ... and initialize these targets */
2727 if (!init_grouping_targets(root, rel, target, agg_input,
2728 &group_clauses, &group_exprs))
2729 return NULL;
2730
2731 /*
2732 * Eager aggregation is not applicable if there are no available grouping
2733 * expressions.
2734 */
2735 if (group_clauses == NIL)
2736 return NULL;
2737
2738 /* Add aggregates to the grouping target */
2739 foreach(lc, root->agg_clause_list)
2740 {
2741 AggClauseInfo *ac_info = lfirst_node(AggClauseInfo, lc);
2742 Aggref *aggref;
2743
2744 Assert(IsA(ac_info->aggref, Aggref));
2745
2746 aggref = (Aggref *) copyObject(ac_info->aggref);
2748
2749 add_column_to_pathtarget(target, (Expr *) aggref, 0);
2750 }
2751
2752 /* Set the estimated eval cost and output width for both targets */
2754 set_pathtarget_cost_width(root, agg_input);
2755
2756 /* build the RelAggInfo result */
2757 result = makeNode(RelAggInfo);
2758 result->target = target;
2759 result->agg_input = agg_input;
2760 result->group_clauses = group_clauses;
2761 result->group_exprs = group_exprs;
2762 result->apply_agg_at = NULL; /* caller will change this later */
2763
2764 if (calculate_grouped_rows)
2765 {
2767 rel->rows, NULL, NULL);
2768
2769 /*
2770 * The grouped paths for the given relation are considered useful iff
2771 * the average group size is no less than min_eager_agg_group_size.
2772 */
2773 result->agg_useful =
2774 (rel->rows / result->grouped_rows) >= min_eager_agg_group_size;
2775 }
2776
2777 return result;
2778}
double min_eager_agg_group_size
Definition: allpaths.c:84
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition: appendinfo.c:592
PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
Definition: costsize.c:6392
@ AGGSPLIT_INITIAL_SERIAL
Definition: nodes.h:389
#define IS_GROUPED_REL(rel)
Definition: pathnodes.h:1161
#define lfirst_node(type, lc)
Definition: pg_list.h:176
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition: planner.c:5762
static bool init_grouping_targets(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, PathTarget *agg_input, List **group_clauses, List **group_exprs)
Definition: relnode.c:2865
static bool eager_aggregation_possible_for_relation(PlannerInfo *root, RelOptInfo *rel)
Definition: relnode.c:2785
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition: selfuncs.c:3768
Aggref * aggref
Definition: pathnodes.h:3373
List * group_exprs
Definition: pathnodes.h:1203
List * group_clauses
Definition: pathnodes.h:1201
struct PathTarget * agg_input
Definition: pathnodes.h:1198
void add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
Definition: tlist.c:695

References add_column_to_pathtarget(), adjust_appendrel_attrs_multilevel(), RelOptInfo::agg_info, RelAggInfo::agg_input, RelAggInfo::agg_useful, AggClauseInfo::aggref, AGGSPLIT_INITIAL_SERIAL, RelAggInfo::apply_agg_at, Assert(), copyObject, create_empty_pathtarget(), eager_aggregation_possible_for_relation(), estimate_num_groups(), 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().

◆ eager_aggregation_possible_for_relation()

static bool eager_aggregation_possible_for_relation ( PlannerInfo root,
RelOptInfo rel 
)
static

Definition at line 2785 of file relnode.c.

2786{
2787 ListCell *lc;
2788 int cur_relid;
2789
2790 /*
2791 * Check to see if the given relation is in the nullable side of an outer
2792 * join. In this case, we cannot push a partial aggregation down to the
2793 * relation, because the NULL-extended rows produced by the outer join
2794 * would not be available when we perform the partial aggregation, while
2795 * with a non-eager-aggregation plan these rows are available for the
2796 * top-level aggregation. Doing so may result in the rows being grouped
2797 * differently than expected, or produce incorrect values from the
2798 * aggregate functions.
2799 */
2800 cur_relid = -1;
2801 while ((cur_relid = bms_next_member(rel->relids, cur_relid)) >= 0)
2802 {
2803 RelOptInfo *baserel = find_base_rel_ignore_join(root, cur_relid);
2804
2805 if (baserel == NULL)
2806 continue; /* ignore outer joins in rel->relids */
2807
2808 if (!bms_is_subset(baserel->nulling_relids, rel->relids))
2809 return false;
2810 }
2811
2812 /*
2813 * For now we don't try to support PlaceHolderVars.
2814 */
2815 foreach(lc, rel->reltarget->exprs)
2816 {
2817 Expr *expr = lfirst(lc);
2818
2819 if (IsA(expr, PlaceHolderVar))
2820 return false;
2821 }
2822
2823 /* Caller should only pass base relations or joins. */
2825 rel->reloptkind == RELOPT_JOINREL);
2826
2827 /*
2828 * Check if all aggregate expressions can be evaluated on this relation
2829 * level.
2830 */
2831 foreach(lc, root->agg_clause_list)
2832 {
2833 AggClauseInfo *ac_info = lfirst_node(AggClauseInfo, lc);
2834
2835 Assert(IsA(ac_info->aggref, Aggref));
2836
2837 /*
2838 * Give up if any aggregate requires relations other than the current
2839 * one. If the aggregate requires the current relation plus
2840 * additional relations, grouping the current relation could make some
2841 * input rows unavailable for the higher aggregate and may reduce the
2842 * number of input rows it receives. If the aggregate does not
2843 * require the current relation at all, it should not be grouped, as
2844 * we do not support joining two grouped relations.
2845 */
2846 if (!bms_is_subset(ac_info->agg_eval_at, rel->relids))
2847 return false;
2848 }
2849
2850 return true;
2851}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1305
RelOptInfo * find_base_rel_ignore_join(PlannerInfo *root, int relid)
Definition: relnode.c:569
Relids agg_eval_at
Definition: pathnodes.h:3376

References AggClauseInfo::agg_eval_at, AggClauseInfo::aggref, Assert(), bms_is_subset(), bms_next_member(), PathTarget::exprs, find_base_rel_ignore_join(), IsA, lfirst, lfirst_node, RelOptInfo::nulling_relids, RelOptInfo::relids, RELOPT_BASEREL, RELOPT_JOINREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, and root.

Referenced by create_rel_agg_info().

◆ expand_planner_arrays()

void expand_planner_arrays ( PlannerInfo root,
int  add_size 
)

Definition at line 177 of file relnode.c.

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

References add_size(), Assert(), 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 
)

Definition at line 1581 of file relnode.c.

1582{
1583 RelOptInfo *upperrel;
1584 ListCell *lc;
1585
1586 /*
1587 * For the moment, our indexing data structure is just a List for each
1588 * relation kind. If we ever get so many of one kind that this stops
1589 * working well, we can improve it. No code outside this function should
1590 * assume anything about how to find a particular upperrel.
1591 */
1592
1593 /* If we already made this upperrel for the query, return it */
1594 foreach(lc, root->upper_rels[kind])
1595 {
1596 upperrel = (RelOptInfo *) lfirst(lc);
1597
1598 if (bms_equal(upperrel->relids, relids))
1599 return upperrel;
1600 }
1601
1602 upperrel = makeNode(RelOptInfo);
1603 upperrel->reloptkind = RELOPT_UPPER_REL;
1604 upperrel->relids = bms_copy(relids);
1605
1606 /* cheap startup cost is interesting iff not all tuples to be retrieved */
1607 upperrel->consider_startup = (root->tuple_fraction > 0);
1608 upperrel->consider_param_startup = false;
1609 upperrel->consider_parallel = false; /* might get changed later */
1610 upperrel->reltarget = create_empty_pathtarget();
1611 upperrel->pathlist = NIL;
1612 upperrel->cheapest_startup_path = NULL;
1613 upperrel->cheapest_total_path = NULL;
1615
1616 root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
1617
1618 return upperrel;
1619}
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
@ RELOPT_UPPER_REL
Definition: pathnodes.h:887

References bms_copy(), bms_equal(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::consider_parallel, RelOptInfo::consider_param_startup, RelOptInfo::consider_startup, create_empty_pathtarget(), lappend(), lfirst, makeNode, NIL, RelOptInfo::pathlist, RelOptInfo::relids, RELOPT_UPPER_REL, RelOptInfo::reloptkind, RelOptInfo::reltarget, 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 
)

Definition at line 569 of file relnode.c.

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

References elog, ERROR, JOIN_INNER, RangeTblEntry::jointype, root, RTE_JOIN, and RangeTblEntry::rtekind.

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 
)

Definition at line 551 of file relnode.c.

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

References root.

Referenced by all_rows_selectable().

◆ find_childrel_parents()

Relids find_childrel_parents ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 1631 of file relnode.c.

1632{
1633 Relids result = NULL;
1634
1636 Assert(rel->relid > 0 && rel->relid < root->simple_rel_array_size);
1637
1638 do
1639 {
1640 AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
1641 Index prelid = appinfo->parent_relid;
1642
1643 result = bms_add_member(result, prelid);
1644
1645 /* traverse up to the parent rel, loop if it's also a child rel */
1646 rel = find_base_rel(root, prelid);
1647 } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
1648
1650
1651 return result;
1652}
unsigned int Index
Definition: c.h:622
Index parent_relid
Definition: pathnodes.h:3192

References Assert(), bms_add_member(), 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 
)

Definition at line 642 of file relnode.c.

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

References bms_equal(), build_join_rel_hash(), 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 
)

Definition at line 2011 of file relnode.c.

2012{
2013 ListCell *lc;
2014
2015 foreach(lc, rel->ppilist)
2016 {
2017 ParamPathInfo *ppi = (ParamPathInfo *) lfirst(lc);
2018
2019 if (bms_equal(ppi->ppi_req_outer, required_outer))
2020 return ppi;
2021 }
2022
2023 return NULL;
2024}
Relids ppi_req_outer
Definition: pathnodes.h:1826

References bms_equal(), lfirst, ParamPathInfo::ppi_req_outer, 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 
)

Definition at line 1978 of file relnode.c.

1979{
1980 ParamPathInfo *ppi;
1981
1982 /* If rel has LATERAL refs, every path for it should account for them */
1983 Assert(bms_is_subset(appendrel->lateral_relids, required_outer));
1984
1985 /* Unparameterized paths have no ParamPathInfo */
1986 if (bms_is_empty(required_outer))
1987 return NULL;
1988
1989 Assert(!bms_overlap(appendrel->relids, required_outer));
1990
1991 /* If we already have a PPI for this parameterization, just return it */
1992 if ((ppi = find_param_path_info(appendrel, required_outer)))
1993 return ppi;
1994
1995 /* Else build the ParamPathInfo */
1996 ppi = makeNode(ParamPathInfo);
1997 ppi->ppi_req_outer = required_outer;
1998 ppi->ppi_rows = 0;
1999 ppi->ppi_clauses = NIL;
2000 ppi->ppi_serials = NULL;
2001 appendrel->ppilist = lappend(appendrel->ppilist, ppi);
2002
2003 return ppi;
2004}
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:581
#define bms_is_empty(a)
Definition: bitmapset.h:118
ParamPathInfo * find_param_path_info(RelOptInfo *rel, Relids required_outer)
Definition: relnode.c:2011
Cardinality ppi_rows
Definition: pathnodes.h:1827
List * ppi_clauses
Definition: pathnodes.h:1828
Bitmapset * ppi_serials
Definition: pathnodes.h:1829

References Assert(), bms_is_empty, bms_is_subset(), bms_overlap(), find_param_path_info(), lappend(), RelOptInfo::lateral_relids, makeNode, NIL, ParamPathInfo::ppi_clauses, ParamPathInfo::ppi_req_outer, ParamPathInfo::ppi_rows, ParamPathInfo::ppi_serials, RelOptInfo::ppilist, and RelOptInfo::relids.

Referenced by create_append_path().

◆ get_baserel_parampathinfo()

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

Definition at line 1667 of file relnode.c.

1669{
1670 ParamPathInfo *ppi;
1671 Relids joinrelids;
1672 List *pclauses;
1673 List *eqclauses;
1674 Bitmapset *pserials;
1675 double rows;
1676 ListCell *lc;
1677
1678 /* If rel has LATERAL refs, every path for it should account for them */
1679 Assert(bms_is_subset(baserel->lateral_relids, required_outer));
1680
1681 /* Unparameterized paths have no ParamPathInfo */
1682 if (bms_is_empty(required_outer))
1683 return NULL;
1684
1685 Assert(!bms_overlap(baserel->relids, required_outer));
1686
1687 /* If we already have a PPI for this parameterization, just return it */
1688 if ((ppi = find_param_path_info(baserel, required_outer)))
1689 return ppi;
1690
1691 /*
1692 * Identify all joinclauses that are movable to this base rel given this
1693 * parameterization.
1694 */
1695 joinrelids = bms_union(baserel->relids, required_outer);
1696 pclauses = NIL;
1697 foreach(lc, baserel->joininfo)
1698 {
1699 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1700
1702 baserel->relids,
1703 joinrelids))
1704 pclauses = lappend(pclauses, rinfo);
1705 }
1706
1707 /*
1708 * Add in joinclauses generated by EquivalenceClasses, too. (These
1709 * necessarily satisfy join_clause_is_movable_into; but in assert-enabled
1710 * builds, let's verify that.)
1711 */
1713 joinrelids,
1714 required_outer,
1715 baserel,
1716 NULL);
1717#ifdef USE_ASSERT_CHECKING
1718 foreach(lc, eqclauses)
1719 {
1720 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1721
1723 baserel->relids,
1724 joinrelids));
1725 }
1726#endif
1727 pclauses = list_concat(pclauses, eqclauses);
1728
1729 /* Compute set of serial numbers of the enforced clauses */
1730 pserials = NULL;
1731 foreach(lc, pclauses)
1732 {
1733 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1734
1735 pserials = bms_add_member(pserials, rinfo->rinfo_serial);
1736 }
1737
1738 /* Estimate the number of rows returned by the parameterized scan */
1739 rows = get_parameterized_baserel_size(root, baserel, pclauses);
1740
1741 /* And now we can build the ParamPathInfo */
1742 ppi = makeNode(ParamPathInfo);
1743 ppi->ppi_req_outer = required_outer;
1744 ppi->ppi_rows = rows;
1745 ppi->ppi_clauses = pclauses;
1746 ppi->ppi_serials = pserials;
1747 baserel->ppilist = lappend(baserel->ppilist, ppi);
1748
1749 return ppi;
1750}
double get_parameterized_baserel_size(PlannerInfo *root, RelOptInfo *rel, List *param_clauses)
Definition: costsize.c:5404
bool join_clause_is_movable_into(RestrictInfo *rinfo, Relids currentrelids, Relids current_and_outer)
Definition: restrictinfo.c:661
int rinfo_serial
Definition: pathnodes.h:2864

References Assert(), bms_add_member(), bms_is_empty, bms_is_subset(), bms_overlap(), bms_union(), find_param_path_info(), generate_join_implied_equalities(), get_parameterized_baserel_size(), join_clause_is_movable_into(), RelOptInfo::joininfo, lappend(), RelOptInfo::lateral_relids, lfirst, list_concat(), makeNode, NIL, ParamPathInfo::ppi_clauses, ParamPathInfo::ppi_req_outer, ParamPathInfo::ppi_rows, ParamPathInfo::ppi_serials, RelOptInfo::ppilist, RelOptInfo::relids, 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_expression_sortgroupref()

static Index get_expression_sortgroupref ( PlannerInfo root,
Expr expr 
)
static

Definition at line 3136 of file relnode.c.

3137{
3138 ListCell *lc;
3139
3140 Assert(IsA(expr, Var));
3141
3142 foreach(lc, root->group_expr_list)
3143 {
3145 ListCell *lc1;
3146
3147 Assert(IsA(ge_info->expr, Var));
3148 Assert(ge_info->sortgroupref > 0);
3149
3150 if (equal(expr, ge_info->expr))
3151 return ge_info->sortgroupref;
3152
3153 if (ge_info->ec == NULL ||
3154 !bms_is_member(((Var *) expr)->varno, ge_info->ec->ec_relids))
3155 continue;
3156
3157 /*
3158 * Scan the EquivalenceClass, looking for a match to the given
3159 * expression. We ignore child members here.
3160 */
3161 foreach(lc1, ge_info->ec->ec_members)
3162 {
3164
3165 /* Child members should not exist in ec_members */
3166 Assert(!em->em_is_child);
3167
3168 if (equal(expr, em->em_expr))
3169 return ge_info->sortgroupref;
3170 }
3171 }
3172
3173 /* no match is found */
3174 return 0;
3175}
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223

References Assert(), bms_is_member(), EquivalenceMember::em_expr, EquivalenceMember::em_is_child, equal(), GroupingExprInfo::expr, IsA, lfirst, lfirst_node, root, and GroupingExprInfo::sortgroupref.

Referenced by init_grouping_targets().

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

Definition at line 1781 of file relnode.c.

1787{
1788 ParamPathInfo *ppi;
1789 Relids join_and_req;
1790 Relids outer_and_req;
1791 Relids inner_and_req;
1792 List *pclauses;
1793 List *eclauses;
1794 List *dropped_ecs;
1795 double rows;
1796 ListCell *lc;
1797
1798 /* If rel has LATERAL refs, every path for it should account for them */
1799 Assert(bms_is_subset(joinrel->lateral_relids, required_outer));
1800
1801 /* Unparameterized paths have no ParamPathInfo or extra join clauses */
1802 if (bms_is_empty(required_outer))
1803 return NULL;
1804
1805 Assert(!bms_overlap(joinrel->relids, required_outer));
1806
1807 /*
1808 * Identify all joinclauses that are movable to this join rel given this
1809 * parameterization. These are the clauses that are movable into this
1810 * join, but not movable into either input path. Treat an unparameterized
1811 * input path as not accepting parameterized clauses (because it won't,
1812 * per the shortcut exit above), even though the joinclause movement rules
1813 * might allow the same clauses to be moved into a parameterized path for
1814 * that rel.
1815 */
1816 join_and_req = bms_union(joinrel->relids, required_outer);
1817 if (outer_path->param_info)
1818 outer_and_req = bms_union(outer_path->parent->relids,
1819 PATH_REQ_OUTER(outer_path));
1820 else
1821 outer_and_req = NULL; /* outer path does not accept parameters */
1822 if (inner_path->param_info)
1823 inner_and_req = bms_union(inner_path->parent->relids,
1824 PATH_REQ_OUTER(inner_path));
1825 else
1826 inner_and_req = NULL; /* inner path does not accept parameters */
1827
1828 pclauses = NIL;
1829 foreach(lc, joinrel->joininfo)
1830 {
1831 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1832
1834 joinrel->relids,
1835 join_and_req) &&
1837 outer_path->parent->relids,
1838 outer_and_req) &&
1840 inner_path->parent->relids,
1841 inner_and_req))
1842 pclauses = lappend(pclauses, rinfo);
1843 }
1844
1845 /* Consider joinclauses generated by EquivalenceClasses, too */
1847 join_and_req,
1848 required_outer,
1849 joinrel,
1850 NULL);
1851 /* We only want ones that aren't movable to lower levels */
1852 dropped_ecs = NIL;
1853 foreach(lc, eclauses)
1854 {
1855 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1856
1858 joinrel->relids,
1859 join_and_req));
1861 outer_path->parent->relids,
1862 outer_and_req))
1863 continue; /* drop if movable into LHS */
1865 inner_path->parent->relids,
1866 inner_and_req))
1867 {
1868 /* drop if movable into RHS, but remember EC for use below */
1869 Assert(rinfo->left_ec == rinfo->right_ec);
1870 dropped_ecs = lappend(dropped_ecs, rinfo->left_ec);
1871 continue;
1872 }
1873 pclauses = lappend(pclauses, rinfo);
1874 }
1875
1876 /*
1877 * EquivalenceClasses are harder to deal with than we could wish, because
1878 * of the fact that a given EC can generate different clauses depending on
1879 * context. Suppose we have an EC {X.X, Y.Y, Z.Z} where X and Y are the
1880 * LHS and RHS of the current join and Z is in required_outer, and further
1881 * suppose that the inner_path is parameterized by both X and Z. The code
1882 * above will have produced either Z.Z = X.X or Z.Z = Y.Y from that EC,
1883 * and in the latter case will have discarded it as being movable into the
1884 * RHS. However, the EC machinery might have produced either Y.Y = X.X or
1885 * Y.Y = Z.Z as the EC enforcement clause within the inner_path; it will
1886 * not have produced both, and we can't readily tell from here which one
1887 * it did pick. If we add no clause to this join, we'll end up with
1888 * insufficient enforcement of the EC; either Z.Z or X.X will fail to be
1889 * constrained to be equal to the other members of the EC. (When we come
1890 * to join Z to this X/Y path, we will certainly drop whichever EC clause
1891 * is generated at that join, so this omission won't get fixed later.)
1892 *
1893 * To handle this, for each EC we discarded such a clause from, try to
1894 * generate a clause connecting the required_outer rels to the join's LHS
1895 * ("Z.Z = X.X" in the terms of the above example). If successful, and if
1896 * the clause can't be moved to the LHS, add it to the current join's
1897 * restriction clauses. (If an EC cannot generate such a clause then it
1898 * has nothing that needs to be enforced here, while if the clause can be
1899 * moved into the LHS then it should have been enforced within that path.)
1900 *
1901 * Note that we don't need similar processing for ECs whose clause was
1902 * considered to be movable into the LHS, because the LHS can't refer to
1903 * the RHS so there is no comparable ambiguity about what it might
1904 * actually be enforcing internally.
1905 */
1906 if (dropped_ecs)
1907 {
1908 Relids real_outer_and_req;
1909
1910 real_outer_and_req = bms_union(outer_path->parent->relids,
1911 required_outer);
1912 eclauses =
1914 dropped_ecs,
1915 real_outer_and_req,
1916 required_outer,
1917 outer_path->parent);
1918 foreach(lc, eclauses)
1919 {
1920 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1921
1923 outer_path->parent->relids,
1924 real_outer_and_req));
1925 if (!join_clause_is_movable_into(rinfo,
1926 outer_path->parent->relids,
1927 outer_and_req))
1928 pclauses = lappend(pclauses, rinfo);
1929 }
1930 }
1931
1932 /*
1933 * Now, attach the identified moved-down clauses to the caller's
1934 * restrict_clauses list. By using list_concat in this order, we leave
1935 * the original list structure of restrict_clauses undamaged.
1936 */
1937 *restrict_clauses = list_concat(pclauses, *restrict_clauses);
1938
1939 /* If we already have a PPI for this parameterization, just return it */
1940 if ((ppi = find_param_path_info(joinrel, required_outer)))
1941 return ppi;
1942
1943 /* Estimate the number of rows returned by the parameterized join */
1944 rows = get_parameterized_joinrel_size(root, joinrel,
1945 outer_path,
1946 inner_path,
1947 sjinfo,
1948 *restrict_clauses);
1949
1950 /*
1951 * And now we can build the ParamPathInfo. No point in saving the
1952 * input-pair-dependent clause list, though.
1953 *
1954 * Note: in GEQO mode, we'll be called in a temporary memory context, but
1955 * the joinrel structure is there too, so no problem.
1956 */
1957 ppi = makeNode(ParamPathInfo);
1958 ppi->ppi_req_outer = required_outer;
1959 ppi->ppi_rows = rows;
1960 ppi->ppi_clauses = NIL;
1961 ppi->ppi_serials = NULL;
1962 joinrel->ppilist = lappend(joinrel->ppilist, ppi);
1963
1964 return ppi;
1965}
double get_parameterized_joinrel_size(PlannerInfo *root, RelOptInfo *rel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, List *restrict_clauses)
Definition: costsize.c:5485
List * generate_join_implied_equalities_for_ecs(PlannerInfo *root, List *eclasses, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel)
Definition: equivclass.c:1650
#define PATH_REQ_OUTER(path)
Definition: pathnodes.h:1917

References Assert(), bms_is_empty, bms_is_subset(), bms_overlap(), bms_union(), 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, ParamPathInfo::ppi_clauses, ParamPathInfo::ppi_req_outer, ParamPathInfo::ppi_rows, ParamPathInfo::ppi_serials, 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)

Definition at line 2032 of file relnode.c.

2033{
2034 if (path->param_info == NULL)
2035 return NULL; /* not parameterized */
2036
2037 /*
2038 * We don't currently support parameterized MergeAppend paths, as
2039 * explained in the comments for generate_orderedappend_paths.
2040 */
2041 Assert(!IsA(path, MergeAppendPath));
2042
2043 if (IsA(path, NestPath) ||
2044 IsA(path, MergePath) ||
2045 IsA(path, HashPath))
2046 {
2047 /*
2048 * For a join path, combine clauses enforced within either input path
2049 * with those enforced as joinrestrictinfo in this path. Note that
2050 * joinrestrictinfo may include some non-pushed-down clauses, but for
2051 * current purposes it's okay if we include those in the result. (To
2052 * be more careful, we could check for clause_relids overlapping the
2053 * path parameterization, but it's not worth the cycles for now.)
2054 */
2055 JoinPath *jpath = (JoinPath *) path;
2056 Bitmapset *pserials;
2057 ListCell *lc;
2058
2059 pserials = NULL;
2060 pserials = bms_add_members(pserials,
2062 pserials = bms_add_members(pserials,
2064 foreach(lc, jpath->joinrestrictinfo)
2065 {
2066 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
2067
2068 pserials = bms_add_member(pserials, rinfo->rinfo_serial);
2069 }
2070 return pserials;
2071 }
2072 else if (IsA(path, AppendPath))
2073 {
2074 /*
2075 * For an appendrel, take the intersection of the sets of clauses
2076 * enforced in each input path.
2077 */
2078 AppendPath *apath = (AppendPath *) path;
2079 Bitmapset *pserials;
2080 ListCell *lc;
2081
2082 pserials = NULL;
2083 foreach(lc, apath->subpaths)
2084 {
2085 Path *subpath = (Path *) lfirst(lc);
2086 Bitmapset *subserials;
2087
2089 if (lc == list_head(apath->subpaths))
2090 pserials = bms_copy(subserials);
2091 else
2092 pserials = bms_int_members(pserials, subserials);
2093 }
2094 return pserials;
2095 }
2096 else
2097 {
2098 /*
2099 * Otherwise, it's a baserel path and we can use the
2100 * previously-computed set of serial numbers.
2101 */
2102 return path->param_info->ppi_serials;
2103 }
2104}
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:1108
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:916
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:311
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
Bitmapset * get_param_path_clause_serials(Path *path)
Definition: relnode.c:2032
List * subpaths
Definition: pathnodes.h:2180
Path * outerjoinpath
Definition: pathnodes.h:2296
Path * innerjoinpath
Definition: pathnodes.h:2297
List * joinrestrictinfo
Definition: pathnodes.h:2299

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

Referenced by create_nestloop_path(), and get_param_path_clause_serials().

◆ have_partkey_equi_join()

static bool have_partkey_equi_join ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo rel1,
RelOptInfo rel2,
JoinType  jointype,
List restrictlist 
)
static

Definition at line 2186 of file relnode.c.

2189{
2190 PartitionScheme part_scheme = rel1->part_scheme;
2191 bool pk_known_equal[PARTITION_MAX_KEYS];
2192 int num_equal_pks;
2193 ListCell *lc;
2194
2195 /*
2196 * This function must only be called when the joined relations have same
2197 * partitioning scheme.
2198 */
2199 Assert(rel1->part_scheme == rel2->part_scheme);
2200 Assert(part_scheme);
2201
2202 /* We use a bool array to track which partkey columns are known equal */
2203 memset(pk_known_equal, 0, sizeof(pk_known_equal));
2204 /* ... as well as a count of how many are known equal */
2205 num_equal_pks = 0;
2206
2207 /* First, look through the join's restriction clauses */
2208 foreach(lc, restrictlist)
2209 {
2211 OpExpr *opexpr;
2212 Expr *expr1;
2213 Expr *expr2;
2214 bool strict_op;
2215 int ipk1;
2216 int ipk2;
2217
2218 /* If processing an outer join, only use its own join clauses. */
2219 if (IS_OUTER_JOIN(jointype) &&
2220 RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids))
2221 continue;
2222
2223 /* Skip clauses which can not be used for a join. */
2224 if (!rinfo->can_join)
2225 continue;
2226
2227 /* Skip clauses which are not equality conditions. */
2228 if (!rinfo->mergeopfamilies && !OidIsValid(rinfo->hashjoinoperator))
2229 continue;
2230
2231 /* Should be OK to assume it's an OpExpr. */
2232 opexpr = castNode(OpExpr, rinfo->clause);
2233
2234 /* Match the operands to the relation. */
2235 if (bms_is_subset(rinfo->left_relids, rel1->relids) &&
2236 bms_is_subset(rinfo->right_relids, rel2->relids))
2237 {
2238 expr1 = linitial(opexpr->args);
2239 expr2 = lsecond(opexpr->args);
2240 }
2241 else if (bms_is_subset(rinfo->left_relids, rel2->relids) &&
2242 bms_is_subset(rinfo->right_relids, rel1->relids))
2243 {
2244 expr1 = lsecond(opexpr->args);
2245 expr2 = linitial(opexpr->args);
2246 }
2247 else
2248 continue;
2249
2250 /*
2251 * Now we need to know whether the join operator is strict; see
2252 * comments in pathnodes.h.
2253 */
2254 strict_op = op_strict(opexpr->opno);
2255
2256 /*
2257 * Vars appearing in the relation's partition keys will not have any
2258 * varnullingrels, but those in expr1 and expr2 will if we're above
2259 * outer joins that could null the respective rels. It's okay to
2260 * match anyway, if the join operator is strict.
2261 */
2262 if (strict_op)
2263 {
2264 if (bms_overlap(rel1->relids, root->outer_join_rels))
2265 expr1 = (Expr *) remove_nulling_relids((Node *) expr1,
2266 root->outer_join_rels,
2267 NULL);
2268 if (bms_overlap(rel2->relids, root->outer_join_rels))
2269 expr2 = (Expr *) remove_nulling_relids((Node *) expr2,
2270 root->outer_join_rels,
2271 NULL);
2272 }
2273
2274 /*
2275 * Only clauses referencing the partition keys are useful for
2276 * partitionwise join.
2277 */
2278 ipk1 = match_expr_to_partition_keys(expr1, rel1, strict_op);
2279 if (ipk1 < 0)
2280 continue;
2281 ipk2 = match_expr_to_partition_keys(expr2, rel2, strict_op);
2282 if (ipk2 < 0)
2283 continue;
2284
2285 /*
2286 * If the clause refers to keys at different ordinal positions, it can
2287 * not be used for partitionwise join.
2288 */
2289 if (ipk1 != ipk2)
2290 continue;
2291
2292 /* Ignore clause if we already proved these keys equal. */
2293 if (pk_known_equal[ipk1])
2294 continue;
2295
2296 /* Reject if the partition key collation differs from the clause's. */
2297 if (rel1->part_scheme->partcollation[ipk1] != opexpr->inputcollid)
2298 return false;
2299
2300 /*
2301 * The clause allows partitionwise join only if it uses the same
2302 * operator family as that specified by the partition key.
2303 */
2304 if (part_scheme->strategy == PARTITION_STRATEGY_HASH)
2305 {
2306 if (!OidIsValid(rinfo->hashjoinoperator) ||
2307 !op_in_opfamily(rinfo->hashjoinoperator,
2308 part_scheme->partopfamily[ipk1]))
2309 continue;
2310 }
2311 else if (!list_member_oid(rinfo->mergeopfamilies,
2312 part_scheme->partopfamily[ipk1]))
2313 continue;
2314
2315 /* Mark the partition key as having an equi-join clause. */
2316 pk_known_equal[ipk1] = true;
2317
2318 /* We can stop examining clauses once we prove all keys equal. */
2319 if (++num_equal_pks == part_scheme->partnatts)
2320 return true;
2321 }
2322
2323 /*
2324 * Also check to see if any keys are known equal by equivclass.c. In most
2325 * cases there would have been a join restriction clause generated from
2326 * any EC that had such knowledge, but there might be no such clause, or
2327 * it might happen to constrain other members of the ECs than the ones we
2328 * are looking for.
2329 */
2330 for (int ipk = 0; ipk < part_scheme->partnatts; ipk++)
2331 {
2332 Oid btree_opfamily;
2333
2334 /* Ignore if we already proved these keys equal. */
2335 if (pk_known_equal[ipk])
2336 continue;
2337
2338 /*
2339 * We need a btree opfamily to ask equivclass.c about. If the
2340 * partopfamily is a hash opfamily, look up its equality operator, and
2341 * select some btree opfamily that that operator is part of. (Any
2342 * such opfamily should be good enough, since equivclass.c will track
2343 * multiple opfamilies as appropriate.)
2344 */
2345 if (part_scheme->strategy == PARTITION_STRATEGY_HASH)
2346 {
2347 Oid eq_op;
2348 List *eq_opfamilies;
2349
2350 eq_op = get_opfamily_member(part_scheme->partopfamily[ipk],
2351 part_scheme->partopcintype[ipk],
2352 part_scheme->partopcintype[ipk],
2354 if (!OidIsValid(eq_op))
2355 break; /* we're not going to succeed */
2356 eq_opfamilies = get_mergejoin_opfamilies(eq_op);
2357 if (eq_opfamilies == NIL)
2358 break; /* we're not going to succeed */
2359 btree_opfamily = linitial_oid(eq_opfamilies);
2360 }
2361 else
2362 btree_opfamily = part_scheme->partopfamily[ipk];
2363
2364 /*
2365 * We consider only non-nullable partition keys here; nullable ones
2366 * would not be treated as part of the same equivalence classes as
2367 * non-nullable ones.
2368 */
2369 foreach(lc, rel1->partexprs[ipk])
2370 {
2371 Node *expr1 = (Node *) lfirst(lc);
2372 ListCell *lc2;
2373 Oid partcoll1 = rel1->part_scheme->partcollation[ipk];
2374 Oid exprcoll1 = exprCollation(expr1);
2375
2376 foreach(lc2, rel2->partexprs[ipk])
2377 {
2378 Node *expr2 = (Node *) lfirst(lc2);
2379
2380 if (exprs_known_equal(root, expr1, expr2, btree_opfamily))
2381 {
2382 /*
2383 * Ensure that the collation of the expression matches
2384 * that of the partition key. Checking just one collation
2385 * (partcoll1 and exprcoll1) suffices because partcoll1
2386 * and partcoll2, as well as exprcoll1 and exprcoll2,
2387 * should be identical. This holds because both rel1 and
2388 * rel2 use the same PartitionScheme and expr1 and expr2
2389 * are equal.
2390 */
2391 if (partcoll1 == exprcoll1)
2392 {
2393 Oid partcoll2 PG_USED_FOR_ASSERTS_ONLY =
2394 rel2->part_scheme->partcollation[ipk];
2395 Oid exprcoll2 PG_USED_FOR_ASSERTS_ONLY =
2396 exprCollation(expr2);
2397
2398 Assert(partcoll2 == exprcoll2);
2399 pk_known_equal[ipk] = true;
2400 break;
2401 }
2402 }
2403 }
2404 if (pk_known_equal[ipk])
2405 break;
2406 }
2407
2408 if (pk_known_equal[ipk])
2409 {
2410 /* We can stop examining keys once we prove all keys equal. */
2411 if (++num_equal_pks == part_scheme->partnatts)
2412 return true;
2413 }
2414 else
2415 break; /* no chance to succeed, give up */
2416 }
2417
2418 return false;
2419}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:228
#define OidIsValid(objectId)
Definition: c.h:777
bool exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2, Oid opfamily)
Definition: equivclass.c:2648
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
bool op_strict(Oid opno)
Definition: lsyscache.c:1644
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:168
List * get_mergejoin_opfamilies(Oid opno)
Definition: lsyscache.c:435
bool op_in_opfamily(Oid opno, Oid opfamily)
Definition: lsyscache.c:68
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:348
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:902
#define RINFO_IS_PUSHED_DOWN(rinfo, joinrelids)
Definition: pathnodes.h:2949
#define PARTITION_MAX_KEYS
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
#define linitial_oid(l)
Definition: pg_list.h:180
unsigned int Oid
Definition: postgres_ext.h:32
static int match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel, bool strict_op)
Definition: relnode.c:2433
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)
#define HTEqualStrategyNumber
Definition: stratnum.h:41
Oid opno
Definition: primnodes.h:850
List * args
Definition: primnodes.h:868
Expr * clause
Definition: pathnodes.h:2792

References OpExpr::args, Assert(), bms_is_subset(), bms_overlap(), castNode, RestrictInfo::clause, exprCollation(), exprs_known_equal(), get_mergejoin_opfamilies(), get_opfamily_member(), HTEqualStrategyNumber, IS_OUTER_JOIN, lfirst, lfirst_node, linitial, linitial_oid, list_member_oid(), lsecond, match_expr_to_partition_keys(), NIL, OidIsValid, op_in_opfamily(), op_strict(), OpExpr::opno, PARTITION_MAX_KEYS, PARTITION_STRATEGY_HASH, PartitionSchemeData::partnatts, PartitionSchemeData::partopcintype, PartitionSchemeData::partopfamily, PG_USED_FOR_ASSERTS_ONLY, RelOptInfo::relids, remove_nulling_relids(), RINFO_IS_PUSHED_DOWN, root, and PartitionSchemeData::strategy.

Referenced by build_joinrel_partition_info().

◆ init_grouping_targets()

static bool init_grouping_targets ( PlannerInfo root,
RelOptInfo rel,
PathTarget target,
PathTarget agg_input,
List **  group_clauses,
List **  group_exprs 
)
static

Definition at line 2865 of file relnode.c.

2868{
2869 ListCell *lc;
2870 List *possibly_dependent = NIL;
2871 Index maxSortGroupRef;
2872
2873 /* Identify the max sortgroupref */
2874 maxSortGroupRef = 0;
2875 foreach(lc, root->processed_tlist)
2876 {
2877 Index ref = ((TargetEntry *) lfirst(lc))->ressortgroupref;
2878
2879 if (ref > maxSortGroupRef)
2880 maxSortGroupRef = ref;
2881 }
2882
2883 /*
2884 * At this point, all Vars from this relation that are needed by upper
2885 * joins or are required in the final targetlist should already be present
2886 * in its reltarget. Therefore, we can safely iterate over this
2887 * relation's reltarget->exprs to construct the PathTarget and grouping
2888 * clauses for the grouped paths.
2889 */
2890 foreach(lc, rel->reltarget->exprs)
2891 {
2892 Expr *expr = (Expr *) lfirst(lc);
2893 Index sortgroupref;
2894
2895 /*
2896 * Given that PlaceHolderVar currently prevents us from doing eager
2897 * aggregation, the source target cannot contain anything more complex
2898 * than a Var.
2899 */
2900 Assert(IsA(expr, Var));
2901
2902 /*
2903 * Get the sortgroupref of the expr if it is found among, or can be
2904 * deduced from, the original grouping expressions.
2905 */
2906 sortgroupref = get_expression_sortgroupref(root, expr);
2907 if (sortgroupref > 0)
2908 {
2909 SortGroupClause *sgc;
2910
2911 /* Find the matching SortGroupClause */
2912 sgc = get_sortgroupref_clause(sortgroupref, root->processed_groupClause);
2913 Assert(sgc->tleSortGroupRef <= maxSortGroupRef);
2914
2915 /*
2916 * If the target expression is to be used as a grouping key, it
2917 * should be emitted by the grouped paths that have been pushed
2918 * down to this relation level.
2919 */
2920 add_column_to_pathtarget(target, expr, sortgroupref);
2921
2922 /*
2923 * ... and it also should be emitted by the input paths.
2924 */
2925 add_column_to_pathtarget(agg_input, expr, sortgroupref);
2926
2927 /*
2928 * Record this SortGroupClause and grouping expression. Note that
2929 * this SortGroupClause might have already been recorded.
2930 */
2931 if (!list_member(*group_clauses, sgc))
2932 {
2933 *group_clauses = lappend(*group_clauses, sgc);
2934 *group_exprs = lappend(*group_exprs, expr);
2935 }
2936 }
2937 else if (is_var_needed_by_join(root, (Var *) expr, rel))
2938 {
2939 /*
2940 * The expression is needed for an upper join but is neither in
2941 * the GROUP BY clause nor derivable from it using EC (otherwise,
2942 * it would have already been included in the targets above). We
2943 * need to create a special SortGroupClause for this expression.
2944 *
2945 * It is important to include such expressions in the grouping
2946 * keys. This is essential to ensure that an aggregated row from
2947 * the partial aggregation matches the other side of the join if
2948 * and only if each row in the partial group does. This ensures
2949 * that all rows within the same partial group share the same
2950 * 'destiny', which is crucial for maintaining correctness.
2951 */
2952 SortGroupClause *sgc;
2953 TypeCacheEntry *tce;
2954 Oid equalimageproc;
2955
2956 /*
2957 * But first, check if equality implies image equality for this
2958 * expression. If not, we cannot use it as a grouping key. See
2959 * comments in create_grouping_expr_infos().
2960 */
2961 tce = lookup_type_cache(exprType((Node *) expr),
2963 if (!OidIsValid(tce->btree_opf) ||
2965 return false;
2966
2967 equalimageproc = get_opfamily_proc(tce->btree_opf,
2968 tce->btree_opintype,
2969 tce->btree_opintype,
2971 if (!OidIsValid(equalimageproc) ||
2972 !DatumGetBool(OidFunctionCall1Coll(equalimageproc,
2973 tce->typcollation,
2975 return false;
2976
2977 /* Create the SortGroupClause. */
2979
2980 /* Initialize the SortGroupClause. */
2981 sgc->tleSortGroupRef = ++maxSortGroupRef;
2983 false, true, false,
2984 &sgc->sortop, &sgc->eqop, NULL,
2985 &sgc->hashable);
2986
2987 /* This expression should be emitted by the grouped paths */
2988 add_column_to_pathtarget(target, expr, sgc->tleSortGroupRef);
2989
2990 /* ... and it also should be emitted by the input paths. */
2991 add_column_to_pathtarget(agg_input, expr, sgc->tleSortGroupRef);
2992
2993 /* Record this SortGroupClause and grouping expression */
2994 *group_clauses = lappend(*group_clauses, sgc);
2995 *group_exprs = lappend(*group_exprs, expr);
2996 }
2997 else if (is_var_in_aggref_only(root, (Var *) expr))
2998 {
2999 /*
3000 * The expression is referenced by an aggregate function pushed
3001 * down to this relation and does not appear elsewhere in the
3002 * targetlist or havingQual. Add it to 'agg_input' but not to
3003 * 'target'.
3004 */
3005 add_new_column_to_pathtarget(agg_input, expr);
3006 }
3007 else
3008 {
3009 /*
3010 * The expression may be functionally dependent on other
3011 * expressions in the target, but we cannot verify this until all
3012 * target expressions have been constructed.
3013 */
3014 possibly_dependent = lappend(possibly_dependent, expr);
3015 }
3016 }
3017
3018 /*
3019 * Now we can verify whether an expression is functionally dependent on
3020 * others.
3021 */
3022 foreach(lc, possibly_dependent)
3023 {
3024 Var *tvar;
3025 List *deps = NIL;
3026 RangeTblEntry *rte;
3027
3028 tvar = lfirst_node(Var, lc);
3029 rte = root->simple_rte_array[tvar->varno];
3030
3031 if (check_functional_grouping(rte->relid, tvar->varno,
3032 tvar->varlevelsup,
3033 target->exprs, &deps))
3034 {
3035 /*
3036 * The expression is functionally dependent on other target
3037 * expressions, so it can be included in the targets. Since it
3038 * will not be used as a grouping key, a sortgroupref is not
3039 * needed for it.
3040 */
3041 add_new_column_to_pathtarget(target, (Expr *) tvar);
3042 add_new_column_to_pathtarget(agg_input, (Expr *) tvar);
3043 }
3044 else
3045 {
3046 /*
3047 * We may arrive here with a grouping expression that is proven
3048 * redundant by EquivalenceClass processing, such as 't1.a' in the
3049 * query below.
3050 *
3051 * select max(t1.c) from t t1, t t2 where t1.a = 1 group by t1.a,
3052 * t1.b;
3053 *
3054 * For now we just give up in this case.
3055 */
3056 return false;
3057 }
3058 }
3059
3060 return true;
3061}
Datum OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
Definition: fmgr.c:1412
bool list_member(const List *list, const void *datum)
Definition: list.c:661
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:889
#define BTEQUALIMAGE_PROC
Definition: nbtree.h:720
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
void get_sort_group_operators(Oid argtype, bool needLT, bool needEQ, bool needGT, Oid *ltOpr, Oid *eqOpr, Oid *gtOpr, bool *isHashable)
Definition: parse_oper.c:181
bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup, List *grouping_columns, List **constraintDeps)
static bool DatumGetBool(Datum X)
Definition: postgres.h:100
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
static Index get_expression_sortgroupref(PlannerInfo *root, Expr *expr)
Definition: relnode.c:3136
static bool is_var_in_aggref_only(PlannerInfo *root, Var *var)
Definition: relnode.c:3069
static bool is_var_needed_by_join(PlannerInfo *root, Var *var, RelOptInfo *rel)
Definition: relnode.c:3108
Index tleSortGroupRef
Definition: parsenodes.h:1469
Oid btree_opintype
Definition: typcache.h:59
Oid typcollation
Definition: typcache.h:48
Index varlevelsup
Definition: primnodes.h:294
SortGroupClause * get_sortgroupref_clause(Index sortref, List *clauses)
Definition: tlist.c:422
void add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
Definition: tlist.c:741
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_BTREE_OPFAMILY
Definition: typcache.h:147

References add_column_to_pathtarget(), add_new_column_to_pathtarget(), Assert(), BTEQUALIMAGE_PROC, TypeCacheEntry::btree_opf, TypeCacheEntry::btree_opintype, check_functional_grouping(), DatumGetBool(), SortGroupClause::eqop, PathTarget::exprs, exprType(), get_expression_sortgroupref(), get_opfamily_proc(), get_sort_group_operators(), get_sortgroupref_clause(), is_var_in_aggref_only(), is_var_needed_by_join(), IsA, lappend(), lfirst, lfirst_node, list_member(), lookup_type_cache(), makeNode, NIL, ObjectIdGetDatum(), OidFunctionCall1Coll(), OidIsValid, RelOptInfo::reltarget, root, SortGroupClause::sortop, SortGroupClause::tleSortGroupRef, TypeCacheEntry::typcollation, TYPECACHE_BTREE_OPFAMILY, Var::varlevelsup, and Var::varno.

Referenced by create_rel_agg_info().

◆ is_var_in_aggref_only()

static bool is_var_in_aggref_only ( PlannerInfo root,
Var var 
)
static

Definition at line 3069 of file relnode.c.

3070{
3071 ListCell *lc;
3072
3073 /*
3074 * Search the list of aggregate expressions for the Var.
3075 */
3076 foreach(lc, root->agg_clause_list)
3077 {
3078 AggClauseInfo *ac_info = lfirst_node(AggClauseInfo, lc);
3079 List *vars;
3080
3081 Assert(IsA(ac_info->aggref, Aggref));
3082
3083 if (!bms_is_member(var->varno, ac_info->agg_eval_at))
3084 continue;
3085
3086 vars = pull_var_clause((Node *) ac_info->aggref,
3090
3091 if (list_member(vars, var))
3092 {
3093 list_free(vars);
3094 break;
3095 }
3096
3097 list_free(vars);
3098 }
3099
3100 return (lc != NULL && !list_member(root->tlist_vars, var));
3101}
void list_free(List *list)
Definition: list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:189
#define PVC_RECURSE_PLACEHOLDERS
Definition: optimizer.h:193
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:191
List * pull_var_clause(Node *node, int flags)
Definition: var.c:653

References AggClauseInfo::agg_eval_at, AggClauseInfo::aggref, Assert(), bms_is_member(), IsA, lfirst_node, list_free(), list_member(), pull_var_clause(), PVC_RECURSE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS, PVC_RECURSE_WINDOWFUNCS, root, and Var::varno.

Referenced by init_grouping_targets().

◆ is_var_needed_by_join()

static bool is_var_needed_by_join ( PlannerInfo root,
Var var,
RelOptInfo rel 
)
static

Definition at line 3108 of file relnode.c.

3109{
3110 Relids relids;
3111 int attno;
3112 RelOptInfo *baserel;
3113
3114 /*
3115 * Note that when checking if the Var is needed by joins above, we want to
3116 * exclude cases where the Var is only needed in the final targetlist. So
3117 * include "relation 0" in the check.
3118 */
3119 relids = bms_copy(rel->relids);
3120 relids = bms_add_member(relids, 0);
3121
3122 baserel = find_base_rel(root, var->varno);
3123 attno = var->varattno - baserel->min_attr;
3124
3125 return bms_nonempty_difference(baserel->attr_needed[attno], relids);
3126}

References bms_add_member(), bms_copy(), bms_nonempty_difference(), find_base_rel(), RelOptInfo::min_attr, RelOptInfo::relids, root, Var::varattno, and Var::varno.

Referenced by init_grouping_targets().

◆ match_expr_to_partition_keys()

static int match_expr_to_partition_keys ( Expr expr,
RelOptInfo rel,
bool  strict_op 
)
static

Definition at line 2433 of file relnode.c.

2434{
2435 int cnt;
2436
2437 /* This function should be called only for partitioned relations. */
2438 Assert(rel->part_scheme);
2439 Assert(rel->partexprs);
2440 Assert(rel->nullable_partexprs);
2441
2442 /* Remove any relabel decorations. */
2443 while (IsA(expr, RelabelType))
2444 expr = (Expr *) (castNode(RelabelType, expr))->arg;
2445
2446 for (cnt = 0; cnt < rel->part_scheme->partnatts; cnt++)
2447 {
2448 ListCell *lc;
2449
2450 /* We can always match to the non-nullable partition keys. */
2451 foreach(lc, rel->partexprs[cnt])
2452 {
2453 if (equal(lfirst(lc), expr))
2454 return cnt;
2455 }
2456
2457 if (!strict_op)
2458 continue;
2459
2460 /*
2461 * If it's a strict join operator then a NULL partition key on one
2462 * side will not join to any partition key on the other side, and in
2463 * particular such a row can't join to a row from a different
2464 * partition on the other side. So, it's okay to search the nullable
2465 * partition keys as well.
2466 */
2467 foreach(lc, rel->nullable_partexprs[cnt])
2468 {
2469 if (equal(lfirst(lc), expr))
2470 return cnt;
2471 }
2472 }
2473
2474 return -1;
2475}
void * arg

References arg, Assert(), castNode, equal(), IsA, and lfirst.

Referenced by have_partkey_equi_join().

◆ min_join_parameterization()

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

Definition at line 1145 of file relnode.c.

1149{
1150 Relids result;
1151
1152 /*
1153 * Basically we just need the union of the inputs' lateral_relids, less
1154 * whatever is already in the join.
1155 *
1156 * It's not immediately obvious that this is a valid way to compute the
1157 * result, because it might seem that we're ignoring possible lateral refs
1158 * of PlaceHolderVars that are due to be computed at the join but not in
1159 * either input. However, because create_lateral_join_info() already
1160 * charged all such PHV refs to each member baserel of the join, they'll
1161 * be accounted for already in the inputs' lateral_relids. Likewise, we
1162 * do not need to worry about doing transitive closure here, because that
1163 * was already accounted for in the original baserel lateral_relids.
1164 */
1165 result = bms_union(outer_rel->lateral_relids, inner_rel->lateral_relids);
1166 result = bms_del_members(result, joinrelids);
1167 return result;
1168}

References bms_del_members(), bms_union(), and RelOptInfo::lateral_relids.

Referenced by build_join_rel(), and join_is_legal().

◆ set_foreign_rel_properties()

static void set_foreign_rel_properties ( RelOptInfo joinrel,
RelOptInfo outer_rel,
RelOptInfo inner_rel 
)
static

Definition at line 704 of file relnode.c.

706{
707 if (OidIsValid(outer_rel->serverid) &&
708 inner_rel->serverid == outer_rel->serverid)
709 {
710 if (inner_rel->userid == outer_rel->userid)
711 {
712 joinrel->serverid = outer_rel->serverid;
713 joinrel->userid = outer_rel->userid;
714 joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent;
715 joinrel->fdwroutine = outer_rel->fdwroutine;
716 }
717 else if (!OidIsValid(inner_rel->userid) &&
718 outer_rel->userid == GetUserId())
719 {
720 joinrel->serverid = outer_rel->serverid;
721 joinrel->userid = outer_rel->userid;
722 joinrel->useridiscurrent = true;
723 joinrel->fdwroutine = outer_rel->fdwroutine;
724 }
725 else if (!OidIsValid(outer_rel->userid) &&
726 inner_rel->userid == GetUserId())
727 {
728 joinrel->serverid = outer_rel->serverid;
729 joinrel->userid = inner_rel->userid;
730 joinrel->useridiscurrent = true;
731 joinrel->fdwroutine = outer_rel->fdwroutine;
732 }
733 }
734}
Oid GetUserId(void)
Definition: miscinit.c:469

References GetUserId(), OidIsValid, RelOptInfo::serverid, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by build_child_join_rel(), and build_join_rel().

◆ set_joinrel_partition_key_exprs()

static void set_joinrel_partition_key_exprs ( RelOptInfo joinrel,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
JoinType  jointype 
)
static

Definition at line 2482 of file relnode.c.

2485{
2486 PartitionScheme part_scheme = joinrel->part_scheme;
2487 int partnatts = part_scheme->partnatts;
2488
2489 joinrel->partexprs = (List **) palloc0(sizeof(List *) * partnatts);
2490 joinrel->nullable_partexprs =
2491 (List **) palloc0(sizeof(List *) * partnatts);
2492
2493 /*
2494 * The joinrel's partition expressions are the same as those of the input
2495 * rels, but we must properly classify them as nullable or not in the
2496 * joinrel's output. (Also, we add some more partition expressions if
2497 * it's a FULL JOIN.)
2498 */
2499 for (int cnt = 0; cnt < partnatts; cnt++)
2500 {
2501 /* mark these const to enforce that we copy them properly */
2502 const List *outer_expr = outer_rel->partexprs[cnt];
2503 const List *outer_null_expr = outer_rel->nullable_partexprs[cnt];
2504 const List *inner_expr = inner_rel->partexprs[cnt];
2505 const List *inner_null_expr = inner_rel->nullable_partexprs[cnt];
2506 List *partexpr = NIL;
2507 List *nullable_partexpr = NIL;
2508 ListCell *lc;
2509
2510 switch (jointype)
2511 {
2512 /*
2513 * A join relation resulting from an INNER join may be
2514 * regarded as partitioned by either of the inner and outer
2515 * relation keys. For example, A INNER JOIN B ON A.a = B.b
2516 * can be regarded as partitioned on either A.a or B.b. So we
2517 * add both keys to the joinrel's partexpr lists. However,
2518 * anything that was already nullable still has to be treated
2519 * as nullable.
2520 */
2521 case JOIN_INNER:
2522 partexpr = list_concat_copy(outer_expr, inner_expr);
2523 nullable_partexpr = list_concat_copy(outer_null_expr,
2524 inner_null_expr);
2525 break;
2526
2527 /*
2528 * A join relation resulting from a SEMI or ANTI join may be
2529 * regarded as partitioned by the outer relation keys. The
2530 * inner relation's keys are no longer interesting; since they
2531 * aren't visible in the join output, nothing could join to
2532 * them.
2533 */
2534 case JOIN_SEMI:
2535 case JOIN_ANTI:
2536 partexpr = list_copy(outer_expr);
2537 nullable_partexpr = list_copy(outer_null_expr);
2538 break;
2539
2540 /*
2541 * A join relation resulting from a LEFT OUTER JOIN likewise
2542 * may be regarded as partitioned on the (non-nullable) outer
2543 * relation keys. The inner (nullable) relation keys are okay
2544 * as partition keys for further joins as long as they involve
2545 * strict join operators.
2546 */
2547 case JOIN_LEFT:
2548 partexpr = list_copy(outer_expr);
2549 nullable_partexpr = list_concat_copy(inner_expr,
2550 outer_null_expr);
2551 nullable_partexpr = list_concat(nullable_partexpr,
2552 inner_null_expr);
2553 break;
2554
2555 /*
2556 * For FULL OUTER JOINs, both relations are nullable, so the
2557 * resulting join relation may be regarded as partitioned on
2558 * either of inner and outer relation keys, but only for joins
2559 * that involve strict join operators.
2560 */
2561 case JOIN_FULL:
2562 nullable_partexpr = list_concat_copy(outer_expr,
2563 inner_expr);
2564 nullable_partexpr = list_concat(nullable_partexpr,
2565 outer_null_expr);
2566 nullable_partexpr = list_concat(nullable_partexpr,
2567 inner_null_expr);
2568
2569 /*
2570 * Also add CoalesceExprs corresponding to each possible
2571 * full-join output variable (that is, left side coalesced to
2572 * right side), so that we can match equijoin expressions
2573 * using those variables. We really only need these for
2574 * columns merged by JOIN USING, and only with the pairs of
2575 * input items that correspond to the data structures that
2576 * parse analysis would build for such variables. But it's
2577 * hard to tell which those are, so just make all the pairs.
2578 * Extra items in the nullable_partexprs list won't cause big
2579 * problems. (It's possible that such items will get matched
2580 * to user-written COALESCEs, but it should still be valid to
2581 * partition on those, since they're going to be either the
2582 * partition column or NULL; it's the same argument as for
2583 * partitionwise nesting of any outer join.) We assume no
2584 * type coercions are needed to make the coalesce expressions,
2585 * since columns of different types won't have gotten
2586 * classified as the same PartitionScheme. Note that we
2587 * intentionally leave out the varnullingrels decoration that
2588 * would ordinarily appear on the Vars inside these
2589 * CoalesceExprs, because have_partkey_equi_join will strip
2590 * varnullingrels from the expressions it will compare to the
2591 * partexprs.
2592 */
2593 foreach(lc, list_concat_copy(outer_expr, outer_null_expr))
2594 {
2595 Node *larg = (Node *) lfirst(lc);
2596 ListCell *lc2;
2597
2598 foreach(lc2, list_concat_copy(inner_expr, inner_null_expr))
2599 {
2600 Node *rarg = (Node *) lfirst(lc2);
2602
2603 c->coalescetype = exprType(larg);
2604 c->coalescecollid = exprCollation(larg);
2605 c->args = list_make2(larg, rarg);
2606 c->location = -1;
2607 nullable_partexpr = lappend(nullable_partexpr, c);
2608 }
2609 }
2610 break;
2611
2612 default:
2613 elog(ERROR, "unrecognized join type: %d", (int) jointype);
2614 }
2615
2616 joinrel->partexprs[cnt] = partexpr;
2617 joinrel->nullable_partexprs[cnt] = nullable_partexpr;
2618 }
2619}
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
List * list_copy(const List *oldlist)
Definition: list.c:1573
@ JOIN_SEMI
Definition: nodes.h:317
@ JOIN_LEFT
Definition: nodes.h:304
@ JOIN_ANTI
Definition: nodes.h:318
#define list_make2(x1, x2)
Definition: pg_list.h:214
char * c

References elog, ERROR, exprCollation(), exprType(), JOIN_ANTI, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, lappend(), lfirst, list_concat(), list_concat_copy(), list_copy(), list_make2, makeNode, NIL, palloc0(), and PartitionSchemeData::partnatts.

Referenced by build_joinrel_partition_info().

◆ setup_simple_rel_arrays()

void setup_simple_rel_arrays ( PlannerInfo root)

Definition at line 108 of file relnode.c.

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

References Assert(), AppendRelInfo::child_relid, elog, ERROR, lfirst, lfirst_node, list_length(), NIL, palloc0(), and root.

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

◆ subbuild_joinrel_joinlist()

static List * subbuild_joinrel_joinlist ( RelOptInfo joinrel,
List joininfo_list,
List new_joininfo 
)
static

Definition at line 1529 of file relnode.c.

1532{
1533 ListCell *l;
1534
1535 /* Expected to be called only for join between parent relations. */
1536 Assert(joinrel->reloptkind == RELOPT_JOINREL);
1537
1538 foreach(l, joininfo_list)
1539 {
1540 RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
1541
1542 if (bms_is_subset(rinfo->required_relids, joinrel->relids))
1543 {
1544 /*
1545 * This clause becomes a restriction clause for the joinrel, since
1546 * it refers to no outside rels. So we can ignore it in this
1547 * routine.
1548 */
1549 }
1550 else
1551 {
1552 /*
1553 * This clause is still a join clause at this level, so add it to
1554 * the new joininfo list, being careful to eliminate duplicates.
1555 * (Since RestrictInfo nodes in different joinlists will have been
1556 * multiply-linked rather than copied, pointer equality should be
1557 * a sufficient test.)
1558 */
1559 new_joininfo = list_append_unique_ptr(new_joininfo, rinfo);
1560 }
1561 }
1562
1563 return new_joininfo;
1564}
List * list_append_unique_ptr(List *list, void *datum)
Definition: list.c:1356
Relids required_relids
Definition: pathnodes.h:2823

References Assert(), bms_is_subset(), lfirst, list_append_unique_ptr(), RelOptInfo::relids, RELOPT_JOINREL, RelOptInfo::reloptkind, and RestrictInfo::required_relids.

Referenced by build_joinrel_joinlist().

◆ subbuild_joinrel_restrictlist()

static List * subbuild_joinrel_restrictlist ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo input_rel,
Relids  both_input_relids,
List new_restrictlist 
)
static

Definition at line 1463 of file relnode.c.

1468{
1469 ListCell *l;
1470
1471 foreach(l, input_rel->joininfo)
1472 {
1473 RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
1474
1475 if (bms_is_subset(rinfo->required_relids, joinrel->relids))
1476 {
1477 /*
1478 * This clause should become a restriction clause for the joinrel,
1479 * since it refers to no outside rels. However, if it's a clone
1480 * clause then it might be too late to evaluate it, so we have to
1481 * check. (If it is too late, just ignore the clause, taking it
1482 * on faith that another clone was or will be selected.) Clone
1483 * clauses should always be outer-join clauses, so we compare
1484 * against both_input_relids.
1485 */
1486 if (rinfo->has_clone || rinfo->is_clone)
1487 {
1488 Assert(!RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids));
1489 if (!bms_is_subset(rinfo->required_relids, both_input_relids))
1490 continue;
1491 if (bms_overlap(rinfo->incompatible_relids, both_input_relids))
1492 continue;
1493 }
1494 else
1495 {
1496 /*
1497 * For non-clone clauses, we just Assert it's OK. These might
1498 * be either join or filter clauses; if it's a join clause
1499 * then it should not refer to the current join's output.
1500 * (There is little point in checking incompatible_relids,
1501 * because it'll be NULL.)
1502 */
1503 Assert(RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids) ||
1505 both_input_relids));
1506 }
1507
1508 /*
1509 * OK, so add it to the list, being careful to eliminate
1510 * duplicates. (Since RestrictInfo nodes in different joinlists
1511 * will have been multiply-linked rather than copied, pointer
1512 * equality should be a sufficient test.)
1513 */
1514 new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo);
1515 }
1516 else
1517 {
1518 /*
1519 * This clause is still a join clause at this level, so we ignore
1520 * it in this routine.
1521 */
1522 }
1523 }
1524
1525 return new_restrictlist;
1526}
Relids incompatible_relids
Definition: pathnodes.h:2826
bool has_clone
Definition: pathnodes.h:2804

References Assert(), bms_is_subset(), bms_overlap(), RestrictInfo::has_clone, RestrictInfo::incompatible_relids, RestrictInfo::is_clone, RelOptInfo::joininfo, lfirst, list_append_unique_ptr(), RelOptInfo::relids, RestrictInfo::required_relids, and RINFO_IS_PUSHED_DOWN.

Referenced by build_joinrel_restrictlist().