PostgreSQL Source Code  git master
relnode.c File Reference
#include "postgres.h"
#include <limits.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/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/placeholder.h"
#include "optimizer/plancat.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
#include "rewrite/rewriteManip.h"
#include "parser/parse_relation.h"
#include "utils/hsearch.h"
#include "utils/lsyscache.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)
 
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)
 
RelOptInfofind_base_rel (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)
 
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)
 

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

606 {
607  /* GEQO requires us to append the new joinrel to the end of the list! */
608  root->join_rel_list = lappend(root->join_rel_list, joinrel);
609 
610  /* store it into the auxiliary hashtable if there is one. */
611  if (root->join_rel_hash)
612  {
613  JoinHashEntry *hentry;
614  bool found;
615 
616  hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
617  &(joinrel->relids),
618  HASH_ENTER,
619  &found);
620  Assert(!found);
621  hentry->join_rel = joinrel;
622  }
623 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
@ HASH_ENTER
Definition: hsearch.h:114
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
RelOptInfo * join_rel
Definition: relnode.c:40
List * join_rel_list
Definition: pathnodes.h:277
Relids relids
Definition: pathnodes.h:856

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

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 
)

Definition at line 858 of file relnode.c.

861 {
862  RelOptInfo *joinrel = makeNode(RelOptInfo);
863  AppendRelInfo **appinfos;
864  int nappinfos;
865 
866  /* Only joins between "other" relations land here. */
867  Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
868 
869  /* The parent joinrel should have consider_partitionwise_join set. */
870  Assert(parent_joinrel->consider_partitionwise_join);
871 
872  /*
873  * Find the AppendRelInfo structures for the child baserels. We'll need
874  * these for computing the child join's relid set, and later for mapping
875  * Vars to the child rel.
876  */
877  appinfos = find_appinfos_by_relids(root,
878  bms_union(outer_rel->relids,
879  inner_rel->relids),
880  &nappinfos);
881 
882  joinrel->reloptkind = RELOPT_OTHER_JOINREL;
883  joinrel->relids = adjust_child_relids(parent_joinrel->relids,
884  nappinfos, appinfos);
885  joinrel->rows = 0;
886  /* cheap startup cost is interesting iff not all tuples to be retrieved */
887  joinrel->consider_startup = (root->tuple_fraction > 0);
888  joinrel->consider_param_startup = false;
889  joinrel->consider_parallel = false;
890  joinrel->reltarget = create_empty_pathtarget();
891  joinrel->pathlist = NIL;
892  joinrel->ppilist = NIL;
893  joinrel->partial_pathlist = NIL;
894  joinrel->cheapest_startup_path = NULL;
895  joinrel->cheapest_total_path = NULL;
896  joinrel->cheapest_unique_path = NULL;
898  joinrel->direct_lateral_relids = NULL;
899  joinrel->lateral_relids = NULL;
900  joinrel->relid = 0; /* indicates not a baserel */
901  joinrel->rtekind = RTE_JOIN;
902  joinrel->min_attr = 0;
903  joinrel->max_attr = 0;
904  joinrel->attr_needed = NULL;
905  joinrel->attr_widths = NULL;
906  joinrel->nulling_relids = NULL;
907  joinrel->lateral_vars = NIL;
908  joinrel->lateral_referencers = NULL;
909  joinrel->indexlist = NIL;
910  joinrel->pages = 0;
911  joinrel->tuples = 0;
912  joinrel->allvisfrac = 0;
913  joinrel->eclass_indexes = NULL;
914  joinrel->subroot = NULL;
915  joinrel->subplan_params = NIL;
916  joinrel->amflags = 0;
917  joinrel->serverid = InvalidOid;
918  joinrel->userid = InvalidOid;
919  joinrel->useridiscurrent = false;
920  joinrel->fdwroutine = NULL;
921  joinrel->fdw_private = NULL;
922  joinrel->baserestrictinfo = NIL;
923  joinrel->baserestrictcost.startup = 0;
924  joinrel->baserestrictcost.per_tuple = 0;
925  joinrel->joininfo = NIL;
926  joinrel->has_eclass_joins = false;
927  joinrel->consider_partitionwise_join = false; /* might get changed later */
928  joinrel->parent = parent_joinrel;
929  joinrel->top_parent = parent_joinrel->top_parent ? parent_joinrel->top_parent : parent_joinrel;
930  joinrel->top_parent_relids = joinrel->top_parent->relids;
931  joinrel->part_scheme = NULL;
932  joinrel->nparts = -1;
933  joinrel->boundinfo = NULL;
934  joinrel->partbounds_merged = false;
935  joinrel->partition_qual = NIL;
936  joinrel->part_rels = NULL;
937  joinrel->live_parts = NULL;
938  joinrel->all_partrels = NULL;
939  joinrel->partexprs = NULL;
940  joinrel->nullable_partexprs = NULL;
941 
942  /* Compute information relevant to foreign relations. */
943  set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
944 
945  /* Set up reltarget struct */
946  build_child_join_reltarget(root, parent_joinrel, joinrel,
947  nappinfos, appinfos);
948 
949  /* Construct joininfo list. */
950  joinrel->joininfo = (List *) adjust_appendrel_attrs(root,
951  (Node *) parent_joinrel->joininfo,
952  nappinfos,
953  appinfos);
954 
955  /*
956  * Lateral relids referred in child join will be same as that referred in
957  * the parent relation.
958  */
959  joinrel->direct_lateral_relids = (Relids) bms_copy(parent_joinrel->direct_lateral_relids);
960  joinrel->lateral_relids = (Relids) bms_copy(parent_joinrel->lateral_relids);
961 
962  /*
963  * If the parent joinrel has pending equivalence classes, so does the
964  * child.
965  */
966  joinrel->has_eclass_joins = parent_joinrel->has_eclass_joins;
967 
968  /* Is the join between partitions itself partitioned? */
969  build_joinrel_partition_info(root, joinrel, outer_rel, inner_rel, sjinfo,
970  restrictlist);
971 
972  /* Child joinrel is parallel safe if parent is parallel safe. */
973  joinrel->consider_parallel = parent_joinrel->consider_parallel;
974 
975  /* Set estimates of the child-joinrel's size. */
976  set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
977  sjinfo, restrictlist);
978 
979  /* We build the join only once. */
980  Assert(!find_join_rel(root, joinrel->relids));
981 
982  /* Add the relation to the PlannerInfo. */
983  add_join_rel(root, joinrel);
984 
985  /*
986  * We might need EquivalenceClass members corresponding to the child join,
987  * so that we can represent sort pathkeys for it. As with children of
988  * baserels, we shouldn't need this unless there are relevant eclass joins
989  * (implying that a merge join might be possible) or pathkeys to sort by.
990  */
991  if (joinrel->has_eclass_joins || has_useful_pathkeys(root, parent_joinrel))
993  nappinfos, appinfos,
994  parent_joinrel, joinrel);
995 
996  pfree(appinfos);
997 
998  return joinrel;
999 }
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition: appendinfo.c:733
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:196
Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
Definition: appendinfo.c:554
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:211
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:80
void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition: costsize.c:5320
void add_child_join_rel_equivalences(PlannerInfo *root, int nappinfos, AppendRelInfo **appinfos, RelOptInfo *parent_joinrel, RelOptInfo *child_joinrel)
Definition: equivclass.c:2743
void pfree(void *pointer)
Definition: mcxt.c:1456
#define makeNode(_type_)
Definition: nodes.h:176
@ RTE_JOIN
Definition: parsenodes.h:1015
bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel)
Definition: pathkeys.c:1987
Bitmapset * Relids
Definition: pathnodes.h:30
@ RELOPT_OTHER_JOINREL
Definition: pathnodes.h:815
#define IS_OTHER_REL(rel)
Definition: pathnodes.h:839
#define NIL
Definition: pg_list.h:68
#define InvalidOid
Definition: postgres_ext.h:36
static void build_joinrel_partition_info(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist)
Definition: relnode.c:1978
RelOptInfo * find_join_rel(PlannerInfo *root, Relids relids)
Definition: relnode.c:505
static void build_child_join_reltarget(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, int nappinfos, AppendRelInfo **appinfos)
Definition: relnode.c:2386
static void set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:567
static void add_join_rel(PlannerInfo *root, RelOptInfo *joinrel)
Definition: relnode.c:605
Definition: pg_list.h:54
Definition: nodes.h:129
Selectivity tuple_fraction
Definition: pathnodes.h:478
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
List * baserestrictinfo
Definition: pathnodes.h:964
bool consider_param_startup
Definition: pathnodes.h:870
List * subplan_params
Definition: pathnodes.h:933
List * ppilist
Definition: pathnodes.h:884
bool useridiscurrent
Definition: pathnodes.h:947
uint32 amflags
Definition: pathnodes.h:937
List * joininfo
Definition: pathnodes.h:970
List * partition_qual
Definition: pathnodes.h:1006
struct PathTarget * reltarget
Definition: pathnodes.h:878
Index relid
Definition: pathnodes.h:903
List * lateral_vars
Definition: pathnodes.h:919
Cardinality tuples
Definition: pathnodes.h:928
bool consider_parallel
Definition: pathnodes.h:872
Relids top_parent_relids
Definition: pathnodes.h:988
bool partbounds_merged
Definition: pathnodes.h:1004
BlockNumber pages
Definition: pathnodes.h:927
Relids lateral_relids
Definition: pathnodes.h:898
List * cheapest_parameterized_paths
Definition: pathnodes.h:889
List * pathlist
Definition: pathnodes.h:883
RelOptKind reloptkind
Definition: pathnodes.h:850
List * indexlist
Definition: pathnodes.h:923
struct Path * cheapest_unique_path
Definition: pathnodes.h:888
Relids lateral_referencers
Definition: pathnodes.h:921
struct Path * cheapest_startup_path
Definition: pathnodes.h:886
QualCost baserestrictcost
Definition: pathnodes.h:966
struct Path * cheapest_total_path
Definition: pathnodes.h:887
Oid userid
Definition: pathnodes.h:945
Bitmapset * eclass_indexes
Definition: pathnodes.h:931
Relids all_partrels
Definition: pathnodes.h:1020
Relids direct_lateral_relids
Definition: pathnodes.h:896
bool has_eclass_joins
Definition: pathnodes.h:972
Oid serverid
Definition: pathnodes.h:943
bool consider_startup
Definition: pathnodes.h:868
Bitmapset * live_parts
Definition: pathnodes.h:1018
bool consider_partitionwise_join
Definition: pathnodes.h:978
List * partial_pathlist
Definition: pathnodes.h:885
PlannerInfo * subroot
Definition: pathnodes.h:932
AttrNumber max_attr
Definition: pathnodes.h:911
Relids nulling_relids
Definition: pathnodes.h:917
double allvisfrac
Definition: pathnodes.h:929
Cardinality rows
Definition: pathnodes.h:862
AttrNumber min_attr
Definition: pathnodes.h:909
RTEKind rtekind
Definition: pathnodes.h:907
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::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, Assert(), RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_copy(), bms_union(), build_child_join_reltarget(), build_joinrel_partition_info(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_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_appinfos_by_relids(), find_join_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::nparts, RelOptInfo::nulling_relids, RelOptInfo::pages, RelOptInfo::partbounds_merged, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, pfree(), RelOptInfo::ppilist, RelOptInfo::relid, RelOptInfo::relids, RELOPT_OTHER_JOINREL, RelOptInfo::reloptkind, RelOptInfo::reltarget, 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, PlannerInfo::tuple_fraction, RelOptInfo::tuples, 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 2386 of file relnode.c.

2391 {
2392  /* Build the targetlist */
2393  childrel->reltarget->exprs = (List *)
2395  (Node *) parentrel->reltarget->exprs,
2396  nappinfos, appinfos);
2397 
2398  /* Set the cost and width fields */
2399  childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
2400  childrel->reltarget->cost.per_tuple = parentrel->reltarget->cost.per_tuple;
2401  childrel->reltarget->width = parentrel->reltarget->width;
2402 }
List * exprs
Definition: pathnodes.h:1501
QualCost cost
Definition: pathnodes.h:1507

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

Referenced by build_child_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 643 of file relnode.c.

650 {
651  RelOptInfo *joinrel;
652  List *restrictlist;
653 
654  /* This function should be used only for join between parents. */
655  Assert(!IS_OTHER_REL(outer_rel) && !IS_OTHER_REL(inner_rel));
656 
657  /*
658  * See if we already have a joinrel for this set of base rels.
659  */
660  joinrel = find_join_rel(root, joinrelids);
661 
662  if (joinrel)
663  {
664  /*
665  * Yes, so we only need to figure the restrictlist for this particular
666  * pair of component relations.
667  */
668  if (restrictlist_ptr)
669  *restrictlist_ptr = build_joinrel_restrictlist(root,
670  joinrel,
671  outer_rel,
672  inner_rel,
673  sjinfo);
674  return joinrel;
675  }
676 
677  /*
678  * Nope, so make one.
679  */
680  joinrel = makeNode(RelOptInfo);
681  joinrel->reloptkind = RELOPT_JOINREL;
682  joinrel->relids = bms_copy(joinrelids);
683  joinrel->rows = 0;
684  /* cheap startup cost is interesting iff not all tuples to be retrieved */
685  joinrel->consider_startup = (root->tuple_fraction > 0);
686  joinrel->consider_param_startup = false;
687  joinrel->consider_parallel = false;
688  joinrel->reltarget = create_empty_pathtarget();
689  joinrel->pathlist = NIL;
690  joinrel->ppilist = NIL;
691  joinrel->partial_pathlist = NIL;
692  joinrel->cheapest_startup_path = NULL;
693  joinrel->cheapest_total_path = NULL;
694  joinrel->cheapest_unique_path = NULL;
696  /* init direct_lateral_relids from children; we'll finish it up below */
697  joinrel->direct_lateral_relids =
698  bms_union(outer_rel->direct_lateral_relids,
699  inner_rel->direct_lateral_relids);
700  joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids,
701  outer_rel, inner_rel);
702  joinrel->relid = 0; /* indicates not a baserel */
703  joinrel->rtekind = RTE_JOIN;
704  joinrel->min_attr = 0;
705  joinrel->max_attr = 0;
706  joinrel->attr_needed = NULL;
707  joinrel->attr_widths = NULL;
708  joinrel->nulling_relids = NULL;
709  joinrel->lateral_vars = NIL;
710  joinrel->lateral_referencers = NULL;
711  joinrel->indexlist = NIL;
712  joinrel->statlist = NIL;
713  joinrel->pages = 0;
714  joinrel->tuples = 0;
715  joinrel->allvisfrac = 0;
716  joinrel->eclass_indexes = NULL;
717  joinrel->subroot = NULL;
718  joinrel->subplan_params = NIL;
719  joinrel->rel_parallel_workers = -1;
720  joinrel->amflags = 0;
721  joinrel->serverid = InvalidOid;
722  joinrel->userid = InvalidOid;
723  joinrel->useridiscurrent = false;
724  joinrel->fdwroutine = NULL;
725  joinrel->fdw_private = NULL;
726  joinrel->unique_for_rels = NIL;
727  joinrel->non_unique_for_rels = NIL;
728  joinrel->baserestrictinfo = NIL;
729  joinrel->baserestrictcost.startup = 0;
730  joinrel->baserestrictcost.per_tuple = 0;
731  joinrel->baserestrict_min_security = UINT_MAX;
732  joinrel->joininfo = NIL;
733  joinrel->has_eclass_joins = false;
734  joinrel->consider_partitionwise_join = false; /* might get changed later */
735  joinrel->parent = NULL;
736  joinrel->top_parent = NULL;
737  joinrel->top_parent_relids = NULL;
738  joinrel->part_scheme = NULL;
739  joinrel->nparts = -1;
740  joinrel->boundinfo = NULL;
741  joinrel->partbounds_merged = false;
742  joinrel->partition_qual = NIL;
743  joinrel->part_rels = NULL;
744  joinrel->live_parts = NULL;
745  joinrel->all_partrels = NULL;
746  joinrel->partexprs = NULL;
747  joinrel->nullable_partexprs = NULL;
748 
749  /* Compute information relevant to the foreign relations. */
750  set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
751 
752  /*
753  * Fill the joinrel's tlist with just the Vars and PHVs that need to be
754  * output from this join (ie, are needed for higher joinclauses or final
755  * output).
756  *
757  * NOTE: the tlist order for a join rel will depend on which pair of outer
758  * and inner rels we first try to build it from. But the contents should
759  * be the same regardless.
760  */
761  build_joinrel_tlist(root, joinrel, outer_rel, sjinfo, pushed_down_joins,
762  (sjinfo->jointype == JOIN_FULL));
763  build_joinrel_tlist(root, joinrel, inner_rel, sjinfo, pushed_down_joins,
764  (sjinfo->jointype != JOIN_INNER));
765  add_placeholders_to_joinrel(root, joinrel, outer_rel, inner_rel, sjinfo);
766 
767  /*
768  * add_placeholders_to_joinrel also took care of adding the ph_lateral
769  * sets of any PlaceHolderVars computed here to direct_lateral_relids, so
770  * now we can finish computing that. This is much like the computation of
771  * the transitively-closed lateral_relids in min_join_parameterization,
772  * except that here we *do* have to consider the added PHVs.
773  */
774  joinrel->direct_lateral_relids =
775  bms_del_members(joinrel->direct_lateral_relids, joinrel->relids);
776 
777  /*
778  * Construct restrict and join clause lists for the new joinrel. (The
779  * caller might or might not need the restrictlist, but I need it anyway
780  * for set_joinrel_size_estimates().)
781  */
782  restrictlist = build_joinrel_restrictlist(root, joinrel,
783  outer_rel, inner_rel,
784  sjinfo);
785  if (restrictlist_ptr)
786  *restrictlist_ptr = restrictlist;
787  build_joinrel_joinlist(joinrel, outer_rel, inner_rel);
788 
789  /*
790  * This is also the right place to check whether the joinrel has any
791  * pending EquivalenceClass joins.
792  */
793  joinrel->has_eclass_joins = has_relevant_eclass_joinclause(root, joinrel);
794 
795  /* Store the partition information. */
796  build_joinrel_partition_info(root, joinrel, outer_rel, inner_rel, sjinfo,
797  restrictlist);
798 
799  /*
800  * Set estimates of the joinrel's size.
801  */
802  set_joinrel_size_estimates(root, joinrel, outer_rel, inner_rel,
803  sjinfo, restrictlist);
804 
805  /*
806  * Set the consider_parallel flag if this joinrel could potentially be
807  * scanned within a parallel worker. If this flag is false for either
808  * inner_rel or outer_rel, then it must be false for the joinrel also.
809  * Even if both are true, there might be parallel-restricted expressions
810  * in the targetlist or quals.
811  *
812  * Note that if there are more than two rels in this relation, they could
813  * be divided between inner_rel and outer_rel in any arbitrary way. We
814  * assume this doesn't matter, because we should hit all the same baserels
815  * and joinclauses while building up to this joinrel no matter which we
816  * take; therefore, we should make the same decision here however we get
817  * here.
818  */
819  if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
820  is_parallel_safe(root, (Node *) restrictlist) &&
821  is_parallel_safe(root, (Node *) joinrel->reltarget->exprs))
822  joinrel->consider_parallel = true;
823 
824  /* Add the joinrel to the PlannerInfo. */
825  add_join_rel(root, joinrel);
826 
827  /*
828  * Also, if dynamic-programming join search is active, add the new joinrel
829  * to the appropriate sublist. Note: you might think the Assert on number
830  * of members should be for equality, but some of the level 1 rels might
831  * have been joinrels already, so we can only assert <=.
832  */
833  if (root->join_rel_level)
834  {
835  Assert(root->join_cur_level > 0);
836  Assert(root->join_cur_level <= bms_num_members(joinrel->relids));
837  root->join_rel_level[root->join_cur_level] =
838  lappend(root->join_rel_level[root->join_cur_level], joinrel);
839  }
840 
841  return joinrel;
842 }
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:685
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:993
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition: clauses.c:670
bool has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
Definition: equivclass.c:3092
@ JOIN_FULL
Definition: nodes.h:306
@ JOIN_INNER
Definition: nodes.h:304
@ RELOPT_JOINREL
Definition: pathnodes.h:813
void add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
Definition: placeholder.c:373
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel, SpecialJoinInfo *sjinfo, List *pushed_down_joins, bool can_null)
Definition: relnode.c:1088
Relids min_join_parameterization(PlannerInfo *root, Relids joinrelids, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:1010
static List * build_joinrel_restrictlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
Definition: relnode.c:1270
static void build_joinrel_joinlist(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition: relnode.c:1307
int join_cur_level
Definition: pathnodes.h:293
List * statlist
Definition: pathnodes.h:925
List * unique_for_rels
Definition: pathnodes.h:956
List * non_unique_for_rels
Definition: pathnodes.h:958
int rel_parallel_workers
Definition: pathnodes.h:935
Index baserestrict_min_security
Definition: pathnodes.h:968
JoinType jointype
Definition: pathnodes.h:2857

References add_join_rel(), add_placeholders_to_joinrel(), 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::cheapest_unique_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::has_eclass_joins, has_relevant_eclass_joinclause(), RelOptInfo::indexlist, InvalidOid, IS_OTHER_REL, is_parallel_safe(), PlannerInfo::join_cur_level, 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::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, 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, PlannerInfo::tuple_fraction, RelOptInfo::tuples, RelOptInfo::unique_for_rels, 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 464 of file relnode.c.

465 {
466  HTAB *hashtab;
467  HASHCTL hash_ctl;
468  ListCell *l;
469 
470  /* Create the hash table */
471  hash_ctl.keysize = sizeof(Relids);
472  hash_ctl.entrysize = sizeof(JoinHashEntry);
473  hash_ctl.hash = bitmap_hash;
474  hash_ctl.match = bitmap_match;
475  hash_ctl.hcxt = CurrentMemoryContext;
476  hashtab = hash_create("JoinRelHashTable",
477  256L,
478  &hash_ctl,
480 
481  /* Insert all the already-existing joinrels */
482  foreach(l, root->join_rel_list)
483  {
484  RelOptInfo *rel = (RelOptInfo *) lfirst(l);
485  JoinHashEntry *hentry;
486  bool found;
487 
488  hentry = (JoinHashEntry *) hash_search(hashtab,
489  &(rel->relids),
490  HASH_ENTER,
491  &found);
492  Assert(!found);
493  hentry->join_rel = rel;
494  }
495 
496  root->join_rel_hash = hashtab;
497 }
uint32 bitmap_hash(const void *key, Size keysize)
Definition: bitmapset.c:1226
int bitmap_match(const void *key1, const void *key2, Size keysize)
Definition: bitmapset.c:1236
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
#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:135
#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:220

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, PlannerInfo::join_rel_list, HASHCTL::keysize, lfirst, HASHCTL::match, and RelOptInfo::relids.

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

1310 {
1311  List *result;
1312 
1313  /*
1314  * Collect all the clauses that syntactically belong above this level,
1315  * eliminating any duplicates (important since we will see many of the
1316  * same clauses arriving from both input relations).
1317  */
1318  result = subbuild_joinrel_joinlist(joinrel, outer_rel->joininfo, NIL);
1319  result = subbuild_joinrel_joinlist(joinrel, inner_rel->joininfo, result);
1320 
1321  joinrel->joininfo = result;
1322 }
static List * subbuild_joinrel_joinlist(RelOptInfo *joinrel, List *joininfo_list, List *new_joininfo)
Definition: relnode.c:1391

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

1982 {
1983  PartitionScheme part_scheme;
1984 
1985  /* Nothing to do if partitionwise join technique is disabled. */
1987  {
1988  Assert(!IS_PARTITIONED_REL(joinrel));
1989  return;
1990  }
1991 
1992  /*
1993  * We can only consider this join as an input to further partitionwise
1994  * joins if (a) the input relations are partitioned and have
1995  * consider_partitionwise_join=true, (b) the partition schemes match, and
1996  * (c) we can identify an equi-join between the partition keys. Note that
1997  * if it were possible for have_partkey_equi_join to return different
1998  * answers for the same joinrel depending on which join ordering we try
1999  * first, this logic would break. That shouldn't happen, though, because
2000  * of the way the query planner deduces implied equalities and reorders
2001  * the joins. Please see optimizer/README for details.
2002  */
2003  if (outer_rel->part_scheme == NULL || inner_rel->part_scheme == NULL ||
2004  !outer_rel->consider_partitionwise_join ||
2005  !inner_rel->consider_partitionwise_join ||
2006  outer_rel->part_scheme != inner_rel->part_scheme ||
2007  !have_partkey_equi_join(root, joinrel, outer_rel, inner_rel,
2008  sjinfo->jointype, restrictlist))
2009  {
2010  Assert(!IS_PARTITIONED_REL(joinrel));
2011  return;
2012  }
2013 
2014  part_scheme = outer_rel->part_scheme;
2015 
2016  /*
2017  * This function will be called only once for each joinrel, hence it
2018  * should not have partitioning fields filled yet.
2019  */
2020  Assert(!joinrel->part_scheme && !joinrel->partexprs &&
2021  !joinrel->nullable_partexprs && !joinrel->part_rels &&
2022  !joinrel->boundinfo);
2023 
2024  /*
2025  * If the join relation is partitioned, it uses the same partitioning
2026  * scheme as the joining relations.
2027  *
2028  * Note: we calculate the partition bounds, number of partitions, and
2029  * child-join relations of the join relation in try_partitionwise_join().
2030  */
2031  joinrel->part_scheme = part_scheme;
2032  set_joinrel_partition_key_exprs(joinrel, outer_rel, inner_rel,
2033  sjinfo->jointype);
2034 
2035  /*
2036  * Set the consider_partitionwise_join flag.
2037  */
2038  Assert(outer_rel->consider_partitionwise_join);
2039  Assert(inner_rel->consider_partitionwise_join);
2040  joinrel->consider_partitionwise_join = true;
2041 }
bool enable_partitionwise_join
Definition: costsize.c:149
#define IS_PARTITIONED_REL(rel)
Definition: pathnodes.h:1041
static void set_joinrel_partition_key_exprs(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinType jointype)
Definition: relnode.c:2242
static bool have_partkey_equi_join(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *rel1, RelOptInfo *rel2, JoinType jointype, List *restrictlist)
Definition: relnode.c:2051

References Assert(), RelOptInfo::consider_partitionwise_join, enable_partitionwise_join, have_partkey_equi_join(), IS_PARTITIONED_REL, SpecialJoinInfo::jointype, 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 1270 of file relnode.c.

1275 {
1276  List *result;
1277  Relids both_input_relids;
1278 
1279  both_input_relids = bms_union(outer_rel->relids, inner_rel->relids);
1280 
1281  /*
1282  * Collect all the clauses that syntactically belong at this level,
1283  * eliminating any duplicates (important since we will see many of the
1284  * same clauses arriving from both input relations).
1285  */
1286  result = subbuild_joinrel_restrictlist(root, joinrel, outer_rel,
1287  both_input_relids, NIL);
1288  result = subbuild_joinrel_restrictlist(root, joinrel, inner_rel,
1289  both_input_relids, result);
1290 
1291  /*
1292  * Add on any clauses derived from EquivalenceClasses. These cannot be
1293  * redundant with the clauses in the joininfo lists, so don't bother
1294  * checking.
1295  */
1296  result = list_concat(result,
1298  joinrel->relids,
1299  outer_rel->relids,
1300  inner_rel,
1301  sjinfo));
1302 
1303  return result;
1304 }
List * generate_join_implied_equalities(PlannerInfo *root, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
Definition: equivclass.c:1381
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
static List * subbuild_joinrel_restrictlist(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *input_rel, Relids both_input_relids, List *new_restrictlist)
Definition: relnode.c:1325

References bms_union(), generate_join_implied_equalities(), list_concat(), NIL, RelOptInfo::relids, 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 1088 of file relnode.c.

1093 {
1094  Relids relids = joinrel->relids;
1095  ListCell *vars;
1096  ListCell *lc;
1097 
1098  foreach(vars, input_rel->reltarget->exprs)
1099  {
1100  Var *var = (Var *) lfirst(vars);
1101 
1102  /*
1103  * For a PlaceHolderVar, we have to look up the PlaceHolderInfo.
1104  */
1105  if (IsA(var, PlaceHolderVar))
1106  {
1107  PlaceHolderVar *phv = (PlaceHolderVar *) var;
1108  PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
1109 
1110  /* Is it still needed above this joinrel? */
1111  if (bms_nonempty_difference(phinfo->ph_needed, relids))
1112  {
1113  /*
1114  * Yup, add it to the output. If this join potentially nulls
1115  * this input, we have to update the PHV's phnullingrels,
1116  * which means making a copy.
1117  */
1118  if (can_null)
1119  {
1120  phv = copyObject(phv);
1121  /* See comments above to understand this logic */
1122  if (sjinfo->ojrelid != 0 &&
1123  bms_is_member(sjinfo->ojrelid, relids) &&
1124  (bms_is_subset(phv->phrels, sjinfo->syn_righthand) ||
1125  (sjinfo->jointype == JOIN_FULL &&
1126  bms_is_subset(phv->phrels, sjinfo->syn_lefthand))))
1128  sjinfo->ojrelid);
1129  foreach(lc, pushed_down_joins)
1130  {
1131  SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
1132 
1133  Assert(bms_is_member(othersj->ojrelid, relids));
1134  if (bms_is_subset(phv->phrels, othersj->syn_righthand))
1136  othersj->ojrelid);
1137  }
1138  phv->phnullingrels =
1139  bms_join(phv->phnullingrels,
1141  relids));
1142  }
1143 
1144  joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
1145  phv);
1146  /* Bubbling up the precomputed result has cost zero */
1147  joinrel->reltarget->width += phinfo->ph_width;
1148  }
1149  continue;
1150  }
1151 
1152  /*
1153  * Otherwise, anything in a baserel or joinrel targetlist ought to be
1154  * a Var. (More general cases can only appear in appendrel child
1155  * rels, which will never be seen here.)
1156  */
1157  if (!IsA(var, Var))
1158  elog(ERROR, "unexpected node type in rel targetlist: %d",
1159  (int) nodeTag(var));
1160 
1161  if (var->varno == ROWID_VAR)
1162  {
1163  /* UPDATE/DELETE/MERGE row identity vars are always needed */
1164  RowIdentityVarInfo *ridinfo = (RowIdentityVarInfo *)
1165  list_nth(root->row_identity_vars, var->varattno - 1);
1166 
1167  /* Update reltarget width estimate from RowIdentityVarInfo */
1168  joinrel->reltarget->width += ridinfo->rowidwidth;
1169  }
1170  else
1171  {
1172  RelOptInfo *baserel;
1173  int ndx;
1174 
1175  /* Get the Var's original base rel */
1176  baserel = find_base_rel(root, var->varno);
1177 
1178  /* Is it still needed above this joinrel? */
1179  ndx = var->varattno - baserel->min_attr;
1180  if (!bms_nonempty_difference(baserel->attr_needed[ndx], relids))
1181  continue; /* nope, skip it */
1182 
1183  /* Update reltarget width estimate from baserel's attr_widths */
1184  joinrel->reltarget->width += baserel->attr_widths[ndx];
1185  }
1186 
1187  /*
1188  * Add the Var to the output. If this join potentially nulls this
1189  * input, we have to update the Var's varnullingrels, which means
1190  * making a copy. But note that we don't ever add nullingrel bits to
1191  * row identity Vars (cf. comments in setrefs.c).
1192  */
1193  if (can_null && var->varno != ROWID_VAR)
1194  {
1195  var = copyObject(var);
1196  /* See comments above to understand this logic */
1197  if (sjinfo->ojrelid != 0 &&
1198  bms_is_member(sjinfo->ojrelid, relids) &&
1199  (bms_is_member(var->varno, sjinfo->syn_righthand) ||
1200  (sjinfo->jointype == JOIN_FULL &&
1201  bms_is_member(var->varno, sjinfo->syn_lefthand))))
1202  var->varnullingrels = bms_add_member(var->varnullingrels,
1203  sjinfo->ojrelid);
1204  foreach(lc, pushed_down_joins)
1205  {
1206  SpecialJoinInfo *othersj = (SpecialJoinInfo *) lfirst(lc);
1207 
1208  Assert(bms_is_member(othersj->ojrelid, relids));
1209  if (bms_is_member(var->varno, othersj->syn_righthand))
1210  var->varnullingrels = bms_add_member(var->varnullingrels,
1211  othersj->ojrelid);
1212  }
1213  var->varnullingrels =
1214  bms_join(var->varnullingrels,
1216  relids));
1217  }
1218 
1219  joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
1220  var);
1221 
1222  /* Vars have cost zero, so no need to adjust reltarget->cost */
1223  }
1224 }
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1051
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:363
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:460
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:753
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:248
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:581
#define ERROR
Definition: elog.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#define copyObject(obj)
Definition: nodes.h:244
#define nodeTag(nodeptr)
Definition: nodes.h:133
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:217
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:405
Relids ph_needed
Definition: pathnodes.h:3053
Relids phnullingrels
Definition: pathnodes.h:2753
List * row_identity_vars
Definition: pathnodes.h:365
Relids commute_above_r
Definition: pathnodes.h:2860
Relids syn_lefthand
Definition: pathnodes.h:2855
Relids syn_righthand
Definition: pathnodes.h:2856
Definition: primnodes.h:226
AttrNumber varattno
Definition: primnodes.h:238
int varno
Definition: primnodes.h:233
Definition: regcomp.c:281

References Assert(), bms_add_member(), bms_intersect(), bms_is_member(), bms_is_subset(), bms_join(), bms_nonempty_difference(), 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, PlannerInfo::row_identity_vars, ROWID_VAR, RowIdentityVarInfo::rowidwidth, SpecialJoinInfo::syn_lefthand, SpecialJoinInfo::syn_righthand, Var::varattno, Var::varno, and PathTarget::width.

Referenced by build_join_rel().

◆ build_simple_rel()

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

Definition at line 191 of file relnode.c.

192 {
193  RelOptInfo *rel;
194  RangeTblEntry *rte;
195 
196  /* Rel should not exist already */
197  Assert(relid > 0 && relid < root->simple_rel_array_size);
198  if (root->simple_rel_array[relid] != NULL)
199  elog(ERROR, "rel %d already exists", relid);
200 
201  /* Fetch RTE for relation */
202  rte = root->simple_rte_array[relid];
203  Assert(rte != NULL);
204 
205  rel = makeNode(RelOptInfo);
207  rel->relids = bms_make_singleton(relid);
208  rel->rows = 0;
209  /* cheap startup cost is interesting iff not all tuples to be retrieved */
210  rel->consider_startup = (root->tuple_fraction > 0);
211  rel->consider_param_startup = false; /* might get changed later */
212  rel->consider_parallel = false; /* might get changed later */
214  rel->pathlist = NIL;
215  rel->ppilist = NIL;
216  rel->partial_pathlist = NIL;
217  rel->cheapest_startup_path = NULL;
218  rel->cheapest_total_path = NULL;
219  rel->cheapest_unique_path = NULL;
221  rel->relid = relid;
222  rel->rtekind = rte->rtekind;
223  /* min_attr, max_attr, attr_needed, attr_widths are set below */
224  rel->lateral_vars = NIL;
225  rel->indexlist = NIL;
226  rel->statlist = NIL;
227  rel->pages = 0;
228  rel->tuples = 0;
229  rel->allvisfrac = 0;
230  rel->eclass_indexes = NULL;
231  rel->subroot = NULL;
232  rel->subplan_params = NIL;
233  rel->rel_parallel_workers = -1; /* set up in get_relation_info */
234  rel->amflags = 0;
235  rel->serverid = InvalidOid;
236  if (rte->rtekind == RTE_RELATION)
237  {
238  Assert(parent == NULL ||
239  parent->rtekind == RTE_RELATION ||
240  parent->rtekind == RTE_SUBQUERY);
241 
242  /*
243  * For any RELATION rte, we need a userid with which to check
244  * permission access. Baserels simply use their own
245  * RTEPermissionInfo's checkAsUser.
246  *
247  * For otherrels normally there's no RTEPermissionInfo, so we use the
248  * parent's, which normally has one. The exceptional case is that the
249  * parent is a subquery, in which case the otherrel will have its own.
250  */
251  if (rel->reloptkind == RELOPT_BASEREL ||
253  parent->rtekind == RTE_SUBQUERY))
254  {
255  RTEPermissionInfo *perminfo;
256 
257  perminfo = getRTEPermissionInfo(root->parse->rteperminfos, rte);
258  rel->userid = perminfo->checkAsUser;
259  }
260  else
261  rel->userid = parent->userid;
262  }
263  else
264  rel->userid = InvalidOid;
265  rel->useridiscurrent = false;
266  rel->fdwroutine = NULL;
267  rel->fdw_private = NULL;
268  rel->unique_for_rels = NIL;
269  rel->non_unique_for_rels = NIL;
270  rel->baserestrictinfo = NIL;
271  rel->baserestrictcost.startup = 0;
272  rel->baserestrictcost.per_tuple = 0;
273  rel->baserestrict_min_security = UINT_MAX;
274  rel->joininfo = NIL;
275  rel->has_eclass_joins = false;
276  rel->consider_partitionwise_join = false; /* might get changed later */
277  rel->part_scheme = NULL;
278  rel->nparts = -1;
279  rel->boundinfo = NULL;
280  rel->partbounds_merged = false;
281  rel->partition_qual = NIL;
282  rel->part_rels = NULL;
283  rel->live_parts = NULL;
284  rel->all_partrels = NULL;
285  rel->partexprs = NULL;
286  rel->nullable_partexprs = NULL;
287 
288  /*
289  * Pass assorted information down the inheritance hierarchy.
290  */
291  if (parent)
292  {
293  /* We keep back-links to immediate parent and topmost parent. */
294  rel->parent = parent;
295  rel->top_parent = parent->top_parent ? parent->top_parent : parent;
296  rel->top_parent_relids = rel->top_parent->relids;
297 
298  /*
299  * A child rel is below the same outer joins as its parent. (We
300  * presume this info was already calculated for the parent.)
301  */
302  rel->nulling_relids = parent->nulling_relids;
303 
304  /*
305  * Also propagate lateral-reference information from appendrel parent
306  * rels to their child rels. We intentionally give each child rel the
307  * same minimum parameterization, even though it's quite possible that
308  * some don't reference all the lateral rels. This is because any
309  * append path for the parent will have to have the same
310  * parameterization for every child anyway, and there's no value in
311  * forcing extra reparameterize_path() calls. Similarly, a lateral
312  * reference to the parent prevents use of otherwise-movable join rels
313  * for each child.
314  *
315  * It's possible for child rels to have their own children, in which
316  * case the topmost parent's lateral info propagates all the way down.
317  */
319  rel->lateral_relids = parent->lateral_relids;
321  }
322  else
323  {
324  rel->parent = NULL;
325  rel->top_parent = NULL;
326  rel->top_parent_relids = NULL;
327  rel->nulling_relids = NULL;
328  rel->direct_lateral_relids = NULL;
329  rel->lateral_relids = NULL;
330  rel->lateral_referencers = NULL;
331  }
332 
333  /* Check type of rtable entry */
334  switch (rte->rtekind)
335  {
336  case RTE_RELATION:
337  /* Table --- retrieve statistics from the system catalogs */
338  get_relation_info(root, rte->relid, rte->inh, rel);
339  break;
340  case RTE_SUBQUERY:
341  case RTE_FUNCTION:
342  case RTE_TABLEFUNC:
343  case RTE_VALUES:
344  case RTE_CTE:
345  case RTE_NAMEDTUPLESTORE:
346 
347  /*
348  * Subquery, function, tablefunc, values list, CTE, or ENR --- set
349  * up attr range and arrays
350  *
351  * Note: 0 is included in range to support whole-row Vars
352  */
353  rel->min_attr = 0;
354  rel->max_attr = list_length(rte->eref->colnames);
355  rel->attr_needed = (Relids *)
356  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
357  rel->attr_widths = (int32 *)
358  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
359  break;
360  case RTE_RESULT:
361  /* RTE_RESULT has no columns, nor could it have whole-row Var */
362  rel->min_attr = 0;
363  rel->max_attr = -1;
364  rel->attr_needed = NULL;
365  rel->attr_widths = NULL;
366  break;
367  default:
368  elog(ERROR, "unrecognized RTE kind: %d",
369  (int) rte->rtekind);
370  break;
371  }
372 
373  /*
374  * Copy the parent's quals to the child, with appropriate substitution of
375  * variables. If any constant false or NULL clauses turn up, we can mark
376  * the child as dummy right away. (We must do this immediately so that
377  * pruning works correctly when recursing in expand_partitioned_rtentry.)
378  */
379  if (parent)
380  {
381  AppendRelInfo *appinfo = root->append_rel_array[relid];
382 
383  Assert(appinfo != NULL);
384  if (!apply_child_basequals(root, parent, rel, rte, appinfo))
385  {
386  /*
387  * Some restriction clause reduced to constant FALSE or NULL after
388  * substitution, so this child need not be scanned.
389  */
390  mark_dummy_rel(rel);
391  }
392  }
393 
394  /* Save the finished struct in the query's simple_rel_array */
395  root->simple_rel_array[relid] = rel;
396 
397  return rel;
398 }
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:171
signed int int32
Definition: c.h:483
bool apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, RelOptInfo *childrel, RangeTblEntry *childRTE, AppendRelInfo *appinfo)
Definition: inherit.c:836
void mark_dummy_rel(RelOptInfo *rel)
Definition: joinrels.c:1363
void * palloc0(Size size)
Definition: mcxt.c:1257
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_CTE
Definition: parsenodes.h:1019
@ RTE_NAMEDTUPLESTORE
Definition: parsenodes.h:1020
@ RTE_VALUES
Definition: parsenodes.h:1018
@ RTE_SUBQUERY
Definition: parsenodes.h:1014
@ RTE_RESULT
Definition: parsenodes.h:1021
@ RTE_FUNCTION
Definition: parsenodes.h:1016
@ RTE_TABLEFUNC
Definition: parsenodes.h:1017
@ RTE_RELATION
Definition: parsenodes.h:1013
@ RELOPT_BASEREL
Definition: pathnodes.h:812
@ RELOPT_OTHER_MEMBER_REL
Definition: pathnodes.h:814
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:117
List * colnames
Definition: primnodes.h:43
Query * parse
Definition: pathnodes.h:199
Alias * eref
Definition: parsenodes.h:1199
RTEKind rtekind
Definition: parsenodes.h:1032

References RelOptInfo::all_partrels, RelOptInfo::allvisfrac, RelOptInfo::amflags, apply_child_basequals(), Assert(), RelOptInfo::baserestrict_min_security, RelOptInfo::baserestrictcost, RelOptInfo::baserestrictinfo, bms_make_singleton(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_path, RTEPermissionInfo::checkAsUser, Alias::colnames, 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(), RangeTblEntry::eref, ERROR, get_relation_info(), getRTEPermissionInfo(), 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::nparts, RelOptInfo::nulling_relids, RelOptInfo::pages, palloc0(), PlannerInfo::parse, RelOptInfo::partbounds_merged, RelOptInfo::partial_pathlist, RelOptInfo::partition_qual, RelOptInfo::pathlist, QualCost::per_tuple, RelOptInfo::ppilist, RelOptInfo::rel_parallel_workers, RangeTblEntry::relid, RelOptInfo::relid, RelOptInfo::relids, RELOPT_BASEREL, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, RelOptInfo::reltarget, 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, PlannerInfo::tuple_fraction, RelOptInfo::tuples, RelOptInfo::unique_for_rels, 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().

◆ expand_planner_arrays()

void expand_planner_arrays ( PlannerInfo root,
int  add_size 
)

Definition at line 162 of file relnode.c.

163 {
164  int new_size;
165 
166  Assert(add_size > 0);
167 
168  new_size = root->simple_rel_array_size + add_size;
169 
170  root->simple_rel_array =
171  repalloc0_array(root->simple_rel_array, RelOptInfo *, root->simple_rel_array_size, new_size);
172 
173  root->simple_rte_array =
174  repalloc0_array(root->simple_rte_array, RangeTblEntry *, root->simple_rel_array_size, new_size);
175 
176  if (root->append_rel_array)
177  root->append_rel_array =
178  repalloc0_array(root->append_rel_array, AppendRelInfo *, root->simple_rel_array_size, new_size);
179  else
180  root->append_rel_array =
181  palloc0_array(AppendRelInfo *, new_size);
182 
183  root->simple_rel_array_size = new_size;
184 }
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:110
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
int simple_rel_array_size
Definition: pathnodes.h:229

References add_size(), Assert(), palloc0_array, repalloc0_array, and PlannerInfo::simple_rel_array_size.

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

1444 {
1445  RelOptInfo *upperrel;
1446  ListCell *lc;
1447 
1448  /*
1449  * For the moment, our indexing data structure is just a List for each
1450  * relation kind. If we ever get so many of one kind that this stops
1451  * working well, we can improve it. No code outside this function should
1452  * assume anything about how to find a particular upperrel.
1453  */
1454 
1455  /* If we already made this upperrel for the query, return it */
1456  foreach(lc, root->upper_rels[kind])
1457  {
1458  upperrel = (RelOptInfo *) lfirst(lc);
1459 
1460  if (bms_equal(upperrel->relids, relids))
1461  return upperrel;
1462  }
1463 
1464  upperrel = makeNode(RelOptInfo);
1465  upperrel->reloptkind = RELOPT_UPPER_REL;
1466  upperrel->relids = bms_copy(relids);
1467 
1468  /* cheap startup cost is interesting iff not all tuples to be retrieved */
1469  upperrel->consider_startup = (root->tuple_fraction > 0);
1470  upperrel->consider_param_startup = false;
1471  upperrel->consider_parallel = false; /* might get changed later */
1472  upperrel->reltarget = create_empty_pathtarget();
1473  upperrel->pathlist = NIL;
1474  upperrel->cheapest_startup_path = NULL;
1475  upperrel->cheapest_total_path = NULL;
1476  upperrel->cheapest_unique_path = NULL;
1477  upperrel->cheapest_parameterized_paths = NIL;
1478 
1479  root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
1480 
1481  return upperrel;
1482 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:97
@ RELOPT_UPPER_REL
Definition: pathnodes.h:816

References bms_copy(), bms_equal(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, RelOptInfo::cheapest_unique_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 PlannerInfo::tuple_fraction.

Referenced by add_rtes_to_flat_rtable(), 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(), make_union_unique(), preprocess_minmax_aggregates(), recurse_set_operations(), 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 432 of file relnode.c.

433 {
434  /* use an unsigned comparison to prevent negative array element access */
435  if ((uint32) relid < (uint32) root->simple_rel_array_size)
436  {
437  RelOptInfo *rel;
438  RangeTblEntry *rte;
439 
440  rel = root->simple_rel_array[relid];
441  if (rel)
442  return rel;
443 
444  /*
445  * We could just return NULL here, but for debugging purposes it seems
446  * best to actually verify that the relid is an outer join and not
447  * something weird.
448  */
449  rte = root->simple_rte_array[relid];
450  if (rte && rte->rtekind == RTE_JOIN && rte->jointype != JOIN_INNER)
451  return NULL;
452  }
453 
454  elog(ERROR, "no relation entry for relid %d", relid);
455 
456  return NULL; /* keep compiler quiet */
457 }
JoinType jointype
Definition: parsenodes.h:1126

References elog(), ERROR, JOIN_INNER, RangeTblEntry::jointype, RTE_JOIN, RangeTblEntry::rtekind, and PlannerInfo::simple_rel_array_size.

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

◆ find_childrel_parents()

Relids find_childrel_parents ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 1494 of file relnode.c.

1495 {
1496  Relids result = NULL;
1497 
1499  Assert(rel->relid > 0 && rel->relid < root->simple_rel_array_size);
1500 
1501  do
1502  {
1503  AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
1504  Index prelid = appinfo->parent_relid;
1505 
1506  result = bms_add_member(result, prelid);
1507 
1508  /* traverse up to the parent rel, loop if it's also a child rel */
1509  rel = find_base_rel(root, prelid);
1510  } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
1511 
1512  Assert(rel->reloptkind == RELOPT_BASEREL);
1513 
1514  return result;
1515 }
unsigned int Index
Definition: c.h:603
Index parent_relid
Definition: pathnodes.h:2928

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

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

506 {
507  /*
508  * Switch to using hash lookup when list grows "too long". The threshold
509  * is arbitrary and is known only here.
510  */
511  if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)
512  build_join_rel_hash(root);
513 
514  /*
515  * Use either hashtable lookup or linear search, as appropriate.
516  *
517  * Note: the seemingly redundant hashkey variable is used to avoid taking
518  * the address of relids; unless the compiler is exceedingly smart, doing
519  * so would force relids out of a register and thus probably slow down the
520  * list-search case.
521  */
522  if (root->join_rel_hash)
523  {
524  Relids hashkey = relids;
525  JoinHashEntry *hentry;
526 
527  hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,
528  &hashkey,
529  HASH_FIND,
530  NULL);
531  if (hentry)
532  return hentry->join_rel;
533  }
534  else
535  {
536  ListCell *l;
537 
538  foreach(l, root->join_rel_list)
539  {
540  RelOptInfo *rel = (RelOptInfo *) lfirst(l);
541 
542  if (bms_equal(rel->relids, relids))
543  return rel;
544  }
545  }
546 
547  return NULL;
548 }
@ HASH_FIND
Definition: hsearch.h:113
static void build_join_rel_hash(PlannerInfo *root)
Definition: relnode.c:464

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

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

1863 {
1864  ListCell *lc;
1865 
1866  foreach(lc, rel->ppilist)
1867  {
1868  ParamPathInfo *ppi = (ParamPathInfo *) lfirst(lc);
1869 
1870  if (bms_equal(ppi->ppi_req_outer, required_outer))
1871  return ppi;
1872  }
1873 
1874  return NULL;
1875 }
Relids ppi_req_outer
Definition: pathnodes.h:1547

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

1830 {
1831  ParamPathInfo *ppi;
1832 
1833  /* If rel has LATERAL refs, every path for it should account for them */
1834  Assert(bms_is_subset(appendrel->lateral_relids, required_outer));
1835 
1836  /* Unparameterized paths have no ParamPathInfo */
1837  if (bms_is_empty(required_outer))
1838  return NULL;
1839 
1840  Assert(!bms_overlap(appendrel->relids, required_outer));
1841 
1842  /* If we already have a PPI for this parameterization, just return it */
1843  if ((ppi = find_param_path_info(appendrel, required_outer)))
1844  return ppi;
1845 
1846  /* Else build the ParamPathInfo */
1847  ppi = makeNode(ParamPathInfo);
1848  ppi->ppi_req_outer = required_outer;
1849  ppi->ppi_rows = 0;
1850  ppi->ppi_clauses = NIL;
1851  ppi->ppi_serials = NULL;
1852  appendrel->ppilist = lappend(appendrel->ppilist, ppi);
1853 
1854  return ppi;
1855 }
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:527
#define bms_is_empty(a)
Definition: bitmapset.h:105
ParamPathInfo * find_param_path_info(RelOptInfo *rel, Relids required_outer)
Definition: relnode.c:1862
Cardinality ppi_rows
Definition: pathnodes.h:1548
List * ppi_clauses
Definition: pathnodes.h:1549
Bitmapset * ppi_serials
Definition: pathnodes.h:1550

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(), and create_merge_append_path().

◆ get_baserel_parampathinfo()

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

Definition at line 1530 of file relnode.c.

1532 {
1533  ParamPathInfo *ppi;
1534  Relids joinrelids;
1535  List *pclauses;
1536  Bitmapset *pserials;
1537  double rows;
1538  ListCell *lc;
1539 
1540  /* If rel has LATERAL refs, every path for it should account for them */
1541  Assert(bms_is_subset(baserel->lateral_relids, required_outer));
1542 
1543  /* Unparameterized paths have no ParamPathInfo */
1544  if (bms_is_empty(required_outer))
1545  return NULL;
1546 
1547  Assert(!bms_overlap(baserel->relids, required_outer));
1548 
1549  /* If we already have a PPI for this parameterization, just return it */
1550  if ((ppi = find_param_path_info(baserel, required_outer)))
1551  return ppi;
1552 
1553  /*
1554  * Identify all joinclauses that are movable to this base rel given this
1555  * parameterization.
1556  */
1557  joinrelids = bms_union(baserel->relids, required_outer);
1558  pclauses = NIL;
1559  foreach(lc, baserel->joininfo)
1560  {
1561  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1562 
1563  if (join_clause_is_movable_into(rinfo,
1564  baserel->relids,
1565  joinrelids))
1566  pclauses = lappend(pclauses, rinfo);
1567  }
1568 
1569  /*
1570  * Add in joinclauses generated by EquivalenceClasses, too. (These
1571  * necessarily satisfy join_clause_is_movable_into.)
1572  */
1573  pclauses = list_concat(pclauses,
1575  joinrelids,
1576  required_outer,
1577  baserel,
1578  NULL));
1579 
1580  /* Compute set of serial numbers of the enforced clauses */
1581  pserials = NULL;
1582  foreach(lc, pclauses)
1583  {
1584  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1585 
1586  pserials = bms_add_member(pserials, rinfo->rinfo_serial);
1587  }
1588 
1589  /* Estimate the number of rows returned by the parameterized scan */
1590  rows = get_parameterized_baserel_size(root, baserel, pclauses);
1591 
1592  /* And now we can build the ParamPathInfo */
1593  ppi = makeNode(ParamPathInfo);
1594  ppi->ppi_req_outer = required_outer;
1595  ppi->ppi_rows = rows;
1596  ppi->ppi_clauses = pclauses;
1597  ppi->ppi_serials = pserials;
1598  baserel->ppilist = lappend(baserel->ppilist, ppi);
1599 
1600  return ppi;
1601 }
double get_parameterized_baserel_size(PlannerInfo *root, RelOptInfo *rel, List *param_clauses)
Definition: costsize.c:5271
bool join_clause_is_movable_into(RestrictInfo *rinfo, Relids currentrelids, Relids current_and_outer)
Definition: restrictinfo.c:670
int rinfo_serial
Definition: pathnodes.h:2598

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, and RestrictInfo::rinfo_serial.

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

◆ get_joinrel_parampathinfo()

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

Definition at line 1632 of file relnode.c.

1638 {
1639  ParamPathInfo *ppi;
1640  Relids join_and_req;
1641  Relids outer_and_req;
1642  Relids inner_and_req;
1643  List *pclauses;
1644  List *eclauses;
1645  List *dropped_ecs;
1646  double rows;
1647  ListCell *lc;
1648 
1649  /* If rel has LATERAL refs, every path for it should account for them */
1650  Assert(bms_is_subset(joinrel->lateral_relids, required_outer));
1651 
1652  /* Unparameterized paths have no ParamPathInfo or extra join clauses */
1653  if (bms_is_empty(required_outer))
1654  return NULL;
1655 
1656  Assert(!bms_overlap(joinrel->relids, required_outer));
1657 
1658  /*
1659  * Identify all joinclauses that are movable to this join rel given this
1660  * parameterization. These are the clauses that are movable into this
1661  * join, but not movable into either input path. Treat an unparameterized
1662  * input path as not accepting parameterized clauses (because it won't,
1663  * per the shortcut exit above), even though the joinclause movement rules
1664  * might allow the same clauses to be moved into a parameterized path for
1665  * that rel.
1666  */
1667  join_and_req = bms_union(joinrel->relids, required_outer);
1668  if (outer_path->param_info)
1669  outer_and_req = bms_union(outer_path->parent->relids,
1670  PATH_REQ_OUTER(outer_path));
1671  else
1672  outer_and_req = NULL; /* outer path does not accept parameters */
1673  if (inner_path->param_info)
1674  inner_and_req = bms_union(inner_path->parent->relids,
1675  PATH_REQ_OUTER(inner_path));
1676  else
1677  inner_and_req = NULL; /* inner path does not accept parameters */
1678 
1679  pclauses = NIL;
1680  foreach(lc, joinrel->joininfo)
1681  {
1682  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1683 
1684  if (join_clause_is_movable_into(rinfo,
1685  joinrel->relids,
1686  join_and_req) &&
1688  outer_path->parent->relids,
1689  outer_and_req) &&
1691  inner_path->parent->relids,
1692  inner_and_req))
1693  pclauses = lappend(pclauses, rinfo);
1694  }
1695 
1696  /* Consider joinclauses generated by EquivalenceClasses, too */
1697  eclauses = generate_join_implied_equalities(root,
1698  join_and_req,
1699  required_outer,
1700  joinrel,
1701  NULL);
1702  /* We only want ones that aren't movable to lower levels */
1703  dropped_ecs = NIL;
1704  foreach(lc, eclauses)
1705  {
1706  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1707 
1709  joinrel->relids,
1710  join_and_req));
1711  if (join_clause_is_movable_into(rinfo,
1712  outer_path->parent->relids,
1713  outer_and_req))
1714  continue; /* drop if movable into LHS */
1715  if (join_clause_is_movable_into(rinfo,
1716  inner_path->parent->relids,
1717  inner_and_req))
1718  {
1719  /* drop if movable into RHS, but remember EC for use below */
1720  Assert(rinfo->left_ec == rinfo->right_ec);
1721  dropped_ecs = lappend(dropped_ecs, rinfo->left_ec);
1722  continue;
1723  }
1724  pclauses = lappend(pclauses, rinfo);
1725  }
1726 
1727  /*
1728  * EquivalenceClasses are harder to deal with than we could wish, because
1729  * of the fact that a given EC can generate different clauses depending on
1730  * context. Suppose we have an EC {X.X, Y.Y, Z.Z} where X and Y are the
1731  * LHS and RHS of the current join and Z is in required_outer, and further
1732  * suppose that the inner_path is parameterized by both X and Z. The code
1733  * above will have produced either Z.Z = X.X or Z.Z = Y.Y from that EC,
1734  * and in the latter case will have discarded it as being movable into the
1735  * RHS. However, the EC machinery might have produced either Y.Y = X.X or
1736  * Y.Y = Z.Z as the EC enforcement clause within the inner_path; it will
1737  * not have produced both, and we can't readily tell from here which one
1738  * it did pick. If we add no clause to this join, we'll end up with
1739  * insufficient enforcement of the EC; either Z.Z or X.X will fail to be
1740  * constrained to be equal to the other members of the EC. (When we come
1741  * to join Z to this X/Y path, we will certainly drop whichever EC clause
1742  * is generated at that join, so this omission won't get fixed later.)
1743  *
1744  * To handle this, for each EC we discarded such a clause from, try to
1745  * generate a clause connecting the required_outer rels to the join's LHS
1746  * ("Z.Z = X.X" in the terms of the above example). If successful, and if
1747  * the clause can't be moved to the LHS, add it to the current join's
1748  * restriction clauses. (If an EC cannot generate such a clause then it
1749  * has nothing that needs to be enforced here, while if the clause can be
1750  * moved into the LHS then it should have been enforced within that path.)
1751  *
1752  * Note that we don't need similar processing for ECs whose clause was
1753  * considered to be movable into the LHS, because the LHS can't refer to
1754  * the RHS so there is no comparable ambiguity about what it might
1755  * actually be enforcing internally.
1756  */
1757  if (dropped_ecs)
1758  {
1759  Relids real_outer_and_req;
1760 
1761  real_outer_and_req = bms_union(outer_path->parent->relids,
1762  required_outer);
1763  eclauses =
1765  dropped_ecs,
1766  real_outer_and_req,
1767  required_outer,
1768  outer_path->parent);
1769  foreach(lc, eclauses)
1770  {
1771  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1772 
1774  outer_path->parent->relids,
1775  real_outer_and_req));
1776  if (!join_clause_is_movable_into(rinfo,
1777  outer_path->parent->relids,
1778  outer_and_req))
1779  pclauses = lappend(pclauses, rinfo);
1780  }
1781  }
1782 
1783  /*
1784  * Now, attach the identified moved-down clauses to the caller's
1785  * restrict_clauses list. By using list_concat in this order, we leave
1786  * the original list structure of restrict_clauses undamaged.
1787  */
1788  *restrict_clauses = list_concat(pclauses, *restrict_clauses);
1789 
1790  /* If we already have a PPI for this parameterization, just return it */
1791  if ((ppi = find_param_path_info(joinrel, required_outer)))
1792  return ppi;
1793 
1794  /* Estimate the number of rows returned by the parameterized join */
1795  rows = get_parameterized_joinrel_size(root, joinrel,
1796  outer_path,
1797  inner_path,
1798  sjinfo,
1799  *restrict_clauses);
1800 
1801  /*
1802  * And now we can build the ParamPathInfo. No point in saving the
1803  * input-pair-dependent clause list, though.
1804  *
1805  * Note: in GEQO mode, we'll be called in a temporary memory context, but
1806  * the joinrel structure is there too, so no problem.
1807  */
1808  ppi = makeNode(ParamPathInfo);
1809  ppi->ppi_req_outer = required_outer;
1810  ppi->ppi_rows = rows;
1811  ppi->ppi_clauses = NIL;
1812  ppi->ppi_serials = NULL;
1813  joinrel->ppilist = lappend(joinrel->ppilist, ppi);
1814 
1815  return ppi;
1816 }
double get_parameterized_joinrel_size(PlannerInfo *root, RelOptInfo *rel, Path *outer_path, Path *inner_path, SpecialJoinInfo *sjinfo, List *restrict_clauses)
Definition: costsize.c:5352
List * generate_join_implied_equalities_for_ecs(PlannerInfo *root, List *eclasses, Relids join_relids, Relids outer_relids, RelOptInfo *inner_rel)
Definition: equivclass.c:1481
#define PATH_REQ_OUTER(path)
Definition: pathnodes.h:1637

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, and RelOptInfo::relids.

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

1884 {
1885  if (path->param_info == NULL)
1886  return NULL; /* not parameterized */
1887  if (IsA(path, NestPath) ||
1888  IsA(path, MergePath) ||
1889  IsA(path, HashPath))
1890  {
1891  /*
1892  * For a join path, combine clauses enforced within either input path
1893  * with those enforced as joinrestrictinfo in this path. Note that
1894  * joinrestrictinfo may include some non-pushed-down clauses, but for
1895  * current purposes it's okay if we include those in the result. (To
1896  * be more careful, we could check for clause_relids overlapping the
1897  * path parameterization, but it's not worth the cycles for now.)
1898  */
1899  JoinPath *jpath = (JoinPath *) path;
1900  Bitmapset *pserials;
1901  ListCell *lc;
1902 
1903  pserials = NULL;
1904  pserials = bms_add_members(pserials,
1906  pserials = bms_add_members(pserials,
1908  foreach(lc, jpath->joinrestrictinfo)
1909  {
1910  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1911 
1912  pserials = bms_add_member(pserials, rinfo->rinfo_serial);
1913  }
1914  return pserials;
1915  }
1916  else if (IsA(path, AppendPath))
1917  {
1918  /*
1919  * For an appendrel, take the intersection of the sets of clauses
1920  * enforced in each input path.
1921  */
1922  AppendPath *apath = (AppendPath *) path;
1923  Bitmapset *pserials;
1924  ListCell *lc;
1925 
1926  pserials = NULL;
1927  foreach(lc, apath->subpaths)
1928  {
1929  Path *subpath = (Path *) lfirst(lc);
1930  Bitmapset *subserials;
1931 
1932  subserials = get_param_path_clause_serials(subpath);
1933  if (lc == list_head(apath->subpaths))
1934  pserials = bms_copy(subserials);
1935  else
1936  pserials = bms_int_members(pserials, subserials);
1937  }
1938  return pserials;
1939  }
1940  else if (IsA(path, MergeAppendPath))
1941  {
1942  /* Same as AppendPath case */
1943  MergeAppendPath *apath = (MergeAppendPath *) path;
1944  Bitmapset *pserials;
1945  ListCell *lc;
1946 
1947  pserials = NULL;
1948  foreach(lc, apath->subpaths)
1949  {
1950  Path *subpath = (Path *) lfirst(lc);
1951  Bitmapset *subserials;
1952 
1953  subserials = get_param_path_clause_serials(subpath);
1954  if (lc == list_head(apath->subpaths))
1955  pserials = bms_copy(subserials);
1956  else
1957  pserials = bms_int_members(pserials, subserials);
1958  }
1959  return pserials;
1960  }
1961  else
1962  {
1963  /*
1964  * Otherwise, it's a baserel path and we can use the
1965  * previously-computed set of serial numbers.
1966  */
1967  return path->param_info->ppi_serials;
1968  }
1969 }
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:835
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:951
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:241
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
Bitmapset * get_param_path_clause_serials(Path *path)
Definition: relnode.c:1883
List * subpaths
Definition: pathnodes.h:1900
Path * outerjoinpath
Definition: pathnodes.h:2042
Path * innerjoinpath
Definition: pathnodes.h:2043
List * joinrestrictinfo
Definition: pathnodes.h:2045

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

Referenced by create_nestloop_path().

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

2054 {
2055  PartitionScheme part_scheme = rel1->part_scheme;
2056  ListCell *lc;
2057  int cnt_pks;
2058  bool pk_has_clause[PARTITION_MAX_KEYS];
2059  bool strict_op;
2060 
2061  /*
2062  * This function must only be called when the joined relations have same
2063  * partitioning scheme.
2064  */
2065  Assert(rel1->part_scheme == rel2->part_scheme);
2066  Assert(part_scheme);
2067 
2068  memset(pk_has_clause, 0, sizeof(pk_has_clause));
2069  foreach(lc, restrictlist)
2070  {
2071  RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
2072  OpExpr *opexpr;
2073  Expr *expr1;
2074  Expr *expr2;
2075  int ipk1;
2076  int ipk2;
2077 
2078  /* If processing an outer join, only use its own join clauses. */
2079  if (IS_OUTER_JOIN(jointype) &&
2080  RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids))
2081  continue;
2082 
2083  /* Skip clauses which can not be used for a join. */
2084  if (!rinfo->can_join)
2085  continue;
2086 
2087  /* Skip clauses which are not equality conditions. */
2088  if (!rinfo->mergeopfamilies && !OidIsValid(rinfo->hashjoinoperator))
2089  continue;
2090 
2091  /* Should be OK to assume it's an OpExpr. */
2092  opexpr = castNode(OpExpr, rinfo->clause);
2093 
2094  /* Match the operands to the relation. */
2095  if (bms_is_subset(rinfo->left_relids, rel1->relids) &&
2096  bms_is_subset(rinfo->right_relids, rel2->relids))
2097  {
2098  expr1 = linitial(opexpr->args);
2099  expr2 = lsecond(opexpr->args);
2100  }
2101  else if (bms_is_subset(rinfo->left_relids, rel2->relids) &&
2102  bms_is_subset(rinfo->right_relids, rel1->relids))
2103  {
2104  expr1 = lsecond(opexpr->args);
2105  expr2 = linitial(opexpr->args);
2106  }
2107  else
2108  continue;
2109 
2110  /*
2111  * Now we need to know whether the join operator is strict; see
2112  * comments in pathnodes.h.
2113  */
2114  strict_op = op_strict(opexpr->opno);
2115 
2116  /*
2117  * Vars appearing in the relation's partition keys will not have any
2118  * varnullingrels, but those in expr1 and expr2 will if we're above
2119  * outer joins that could null the respective rels. It's okay to
2120  * match anyway, if the join operator is strict.
2121  */
2122  if (strict_op)
2123  {
2124  if (bms_overlap(rel1->relids, root->outer_join_rels))
2125  expr1 = (Expr *) remove_nulling_relids((Node *) expr1,
2126  root->outer_join_rels,
2127  NULL);
2128  if (bms_overlap(rel2->relids, root->outer_join_rels))
2129  expr2 = (Expr *) remove_nulling_relids((Node *) expr2,
2130  root->outer_join_rels,
2131  NULL);
2132  }
2133 
2134  /*
2135  * Only clauses referencing the partition keys are useful for
2136  * partitionwise join.
2137  */
2138  ipk1 = match_expr_to_partition_keys(expr1, rel1, strict_op);
2139  if (ipk1 < 0)
2140  continue;
2141  ipk2 = match_expr_to_partition_keys(expr2, rel2, strict_op);
2142  if (ipk2 < 0)
2143  continue;
2144 
2145  /*
2146  * If the clause refers to keys at different ordinal positions, it can
2147  * not be used for partitionwise join.
2148  */
2149  if (ipk1 != ipk2)
2150  continue;
2151 
2152  /*
2153  * The clause allows partitionwise join only if it uses the same
2154  * operator family as that specified by the partition key.
2155  */
2156  if (rel1->part_scheme->strategy == PARTITION_STRATEGY_HASH)
2157  {
2158  if (!OidIsValid(rinfo->hashjoinoperator) ||
2159  !op_in_opfamily(rinfo->hashjoinoperator,
2160  part_scheme->partopfamily[ipk1]))
2161  continue;
2162  }
2163  else if (!list_member_oid(rinfo->mergeopfamilies,
2164  part_scheme->partopfamily[ipk1]))
2165  continue;
2166 
2167  /* Mark the partition key as having an equi-join clause. */
2168  pk_has_clause[ipk1] = true;
2169  }
2170 
2171  /* Check whether every partition key has an equi-join condition. */
2172  for (cnt_pks = 0; cnt_pks < part_scheme->partnatts; cnt_pks++)
2173  {
2174  if (!pk_has_clause[cnt_pks])
2175  return false;
2176  }
2177 
2178  return true;
2179 }
#define OidIsValid(objectId)
Definition: c.h:764
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721
bool op_strict(Oid opno)
Definition: lsyscache.c:1481
bool op_in_opfamily(Oid opno, Oid opfamily)
Definition: lsyscache.c:65
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:348
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:868
#define RINFO_IS_PUSHED_DOWN(rinfo, joinrelids)
Definition: pathnodes.h:2683
#define PARTITION_MAX_KEYS
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
static int match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel, bool strict_op)
Definition: relnode.c:2193
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)
Oid opno
Definition: primnodes.h:745
List * args
Definition: primnodes.h:763
Relids outer_join_rels
Definition: pathnodes.h:258
Expr * clause
Definition: pathnodes.h:2529

References OpExpr::args, Assert(), bms_is_subset(), bms_overlap(), castNode, RestrictInfo::clause, IS_OUTER_JOIN, lfirst_node, linitial, list_member_oid(), lsecond, match_expr_to_partition_keys(), OidIsValid, op_in_opfamily(), op_strict(), OpExpr::opno, PlannerInfo::outer_join_rels, PARTITION_MAX_KEYS, PARTITION_STRATEGY_HASH, PartitionSchemeData::partnatts, PartitionSchemeData::partopfamily, RelOptInfo::relids, remove_nulling_relids(), and RINFO_IS_PUSHED_DOWN.

Referenced by build_joinrel_partition_info().

◆ match_expr_to_partition_keys()

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

Definition at line 2193 of file relnode.c.

2194 {
2195  int cnt;
2196 
2197  /* This function should be called only for partitioned relations. */
2198  Assert(rel->part_scheme);
2199  Assert(rel->partexprs);
2200  Assert(rel->nullable_partexprs);
2201 
2202  /* Remove any relabel decorations. */
2203  while (IsA(expr, RelabelType))
2204  expr = (Expr *) (castNode(RelabelType, expr))->arg;
2205 
2206  for (cnt = 0; cnt < rel->part_scheme->partnatts; cnt++)
2207  {
2208  ListCell *lc;
2209 
2210  /* We can always match to the non-nullable partition keys. */
2211  foreach(lc, rel->partexprs[cnt])
2212  {
2213  if (equal(lfirst(lc), expr))
2214  return cnt;
2215  }
2216 
2217  if (!strict_op)
2218  continue;
2219 
2220  /*
2221  * If it's a strict join operator then a NULL partition key on one
2222  * side will not join to any partition key on the other side, and in
2223  * particular such a row can't join to a row from a different
2224  * partition on the other side. So, it's okay to search the nullable
2225  * partition keys as well.
2226  */
2227  foreach(lc, rel->nullable_partexprs[cnt])
2228  {
2229  if (equal(lfirst(lc), expr))
2230  return cnt;
2231  }
2232  }
2233 
2234  return -1;
2235 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
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 1010 of file relnode.c.

1014 {
1015  Relids result;
1016 
1017  /*
1018  * Basically we just need the union of the inputs' lateral_relids, less
1019  * whatever is already in the join.
1020  *
1021  * It's not immediately obvious that this is a valid way to compute the
1022  * result, because it might seem that we're ignoring possible lateral refs
1023  * of PlaceHolderVars that are due to be computed at the join but not in
1024  * either input. However, because create_lateral_join_info() already
1025  * charged all such PHV refs to each member baserel of the join, they'll
1026  * be accounted for already in the inputs' lateral_relids. Likewise, we
1027  * do not need to worry about doing transitive closure here, because that
1028  * was already accounted for in the original baserel lateral_relids.
1029  */
1030  result = bms_union(outer_rel->lateral_relids, inner_rel->lateral_relids);
1031  result = bms_del_members(result, joinrelids);
1032  return result;
1033 }

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

569 {
570  if (OidIsValid(outer_rel->serverid) &&
571  inner_rel->serverid == outer_rel->serverid)
572  {
573  if (inner_rel->userid == outer_rel->userid)
574  {
575  joinrel->serverid = outer_rel->serverid;
576  joinrel->userid = outer_rel->userid;
577  joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent;
578  joinrel->fdwroutine = outer_rel->fdwroutine;
579  }
580  else if (!OidIsValid(inner_rel->userid) &&
581  outer_rel->userid == GetUserId())
582  {
583  joinrel->serverid = outer_rel->serverid;
584  joinrel->userid = outer_rel->userid;
585  joinrel->useridiscurrent = true;
586  joinrel->fdwroutine = outer_rel->fdwroutine;
587  }
588  else if (!OidIsValid(outer_rel->userid) &&
589  inner_rel->userid == GetUserId())
590  {
591  joinrel->serverid = outer_rel->serverid;
592  joinrel->userid = inner_rel->userid;
593  joinrel->useridiscurrent = true;
594  joinrel->fdwroutine = outer_rel->fdwroutine;
595  }
596  }
597 }
Oid GetUserId(void)
Definition: miscinit.c:509

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

2245 {
2246  PartitionScheme part_scheme = joinrel->part_scheme;
2247  int partnatts = part_scheme->partnatts;
2248 
2249  joinrel->partexprs = (List **) palloc0(sizeof(List *) * partnatts);
2250  joinrel->nullable_partexprs =
2251  (List **) palloc0(sizeof(List *) * partnatts);
2252 
2253  /*
2254  * The joinrel's partition expressions are the same as those of the input
2255  * rels, but we must properly classify them as nullable or not in the
2256  * joinrel's output. (Also, we add some more partition expressions if
2257  * it's a FULL JOIN.)
2258  */
2259  for (int cnt = 0; cnt < partnatts; cnt++)
2260  {
2261  /* mark these const to enforce that we copy them properly */
2262  const List *outer_expr = outer_rel->partexprs[cnt];
2263  const List *outer_null_expr = outer_rel->nullable_partexprs[cnt];
2264  const List *inner_expr = inner_rel->partexprs[cnt];
2265  const List *inner_null_expr = inner_rel->nullable_partexprs[cnt];
2266  List *partexpr = NIL;
2267  List *nullable_partexpr = NIL;
2268  ListCell *lc;
2269 
2270  switch (jointype)
2271  {
2272  /*
2273  * A join relation resulting from an INNER join may be
2274  * regarded as partitioned by either of the inner and outer
2275  * relation keys. For example, A INNER JOIN B ON A.a = B.b
2276  * can be regarded as partitioned on either A.a or B.b. So we
2277  * add both keys to the joinrel's partexpr lists. However,
2278  * anything that was already nullable still has to be treated
2279  * as nullable.
2280  */
2281  case JOIN_INNER:
2282  partexpr = list_concat_copy(outer_expr, inner_expr);
2283  nullable_partexpr = list_concat_copy(outer_null_expr,
2284  inner_null_expr);
2285  break;
2286 
2287  /*
2288  * A join relation resulting from a SEMI or ANTI join may be
2289  * regarded as partitioned by the outer relation keys. The
2290  * inner relation's keys are no longer interesting; since they
2291  * aren't visible in the join output, nothing could join to
2292  * them.
2293  */
2294  case JOIN_SEMI:
2295  case JOIN_ANTI:
2296  partexpr = list_copy(outer_expr);
2297  nullable_partexpr = list_copy(outer_null_expr);
2298  break;
2299 
2300  /*
2301  * A join relation resulting from a LEFT OUTER JOIN likewise
2302  * may be regarded as partitioned on the (non-nullable) outer
2303  * relation keys. The inner (nullable) relation keys are okay
2304  * as partition keys for further joins as long as they involve
2305  * strict join operators.
2306  */
2307  case JOIN_LEFT:
2308  partexpr = list_copy(outer_expr);
2309  nullable_partexpr = list_concat_copy(inner_expr,
2310  outer_null_expr);
2311  nullable_partexpr = list_concat(nullable_partexpr,
2312  inner_null_expr);
2313  break;
2314 
2315  /*
2316  * For FULL OUTER JOINs, both relations are nullable, so the
2317  * resulting join relation may be regarded as partitioned on
2318  * either of inner and outer relation keys, but only for joins
2319  * that involve strict join operators.
2320  */
2321  case JOIN_FULL:
2322  nullable_partexpr = list_concat_copy(outer_expr,
2323  inner_expr);
2324  nullable_partexpr = list_concat(nullable_partexpr,
2325  outer_null_expr);
2326  nullable_partexpr = list_concat(nullable_partexpr,
2327  inner_null_expr);
2328 
2329  /*
2330  * Also add CoalesceExprs corresponding to each possible
2331  * full-join output variable (that is, left side coalesced to
2332  * right side), so that we can match equijoin expressions
2333  * using those variables. We really only need these for
2334  * columns merged by JOIN USING, and only with the pairs of
2335  * input items that correspond to the data structures that
2336  * parse analysis would build for such variables. But it's
2337  * hard to tell which those are, so just make all the pairs.
2338  * Extra items in the nullable_partexprs list won't cause big
2339  * problems. (It's possible that such items will get matched
2340  * to user-written COALESCEs, but it should still be valid to
2341  * partition on those, since they're going to be either the
2342  * partition column or NULL; it's the same argument as for
2343  * partitionwise nesting of any outer join.) We assume no
2344  * type coercions are needed to make the coalesce expressions,
2345  * since columns of different types won't have gotten
2346  * classified as the same PartitionScheme. Note that we
2347  * intentionally leave out the varnullingrels decoration that
2348  * would ordinarily appear on the Vars inside these
2349  * CoalesceExprs, because have_partkey_equi_join will strip
2350  * varnullingrels from the expressions it will compare to the
2351  * partexprs.
2352  */
2353  foreach(lc, list_concat_copy(outer_expr, outer_null_expr))
2354  {
2355  Node *larg = (Node *) lfirst(lc);
2356  ListCell *lc2;
2357 
2358  foreach(lc2, list_concat_copy(inner_expr, inner_null_expr))
2359  {
2360  Node *rarg = (Node *) lfirst(lc2);
2362 
2363  c->coalescetype = exprType(larg);
2364  c->coalescecollid = exprCollation(larg);
2365  c->args = list_make2(larg, rarg);
2366  c->location = -1;
2367  nullable_partexpr = lappend(nullable_partexpr, c);
2368  }
2369  }
2370  break;
2371 
2372  default:
2373  elog(ERROR, "unrecognized join type: %d", (int) jointype);
2374  }
2375 
2376  joinrel->partexprs[cnt] = partexpr;
2377  joinrel->nullable_partexprs[cnt] = nullable_partexpr;
2378  }
2379 }
List * list_copy(const List *oldlist)
Definition: list.c:1572
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:597
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:786
@ JOIN_SEMI
Definition: nodes.h:318
@ JOIN_LEFT
Definition: nodes.h:305
@ JOIN_ANTI
Definition: nodes.h:319
#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 93 of file relnode.c.

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

References PlannerInfo::append_rel_list, Assert(), AppendRelInfo::child_relid, elog(), ERROR, lfirst, lfirst_node, list_length(), NIL, palloc0(), PlannerInfo::parse, Query::rtable, and PlannerInfo::simple_rel_array_size.

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

1394 {
1395  ListCell *l;
1396 
1397  /* Expected to be called only for join between parent relations. */
1398  Assert(joinrel->reloptkind == RELOPT_JOINREL);
1399 
1400  foreach(l, joininfo_list)
1401  {
1402  RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
1403 
1404  if (bms_is_subset(rinfo->required_relids, joinrel->relids))
1405  {
1406  /*
1407  * This clause becomes a restriction clause for the joinrel, since
1408  * it refers to no outside rels. So we can ignore it in this
1409  * routine.
1410  */
1411  }
1412  else
1413  {
1414  /*
1415  * This clause is still a join clause at this level, so add it to
1416  * the new joininfo list, being careful to eliminate duplicates.
1417  * (Since RestrictInfo nodes in different joinlists will have been
1418  * multiply-linked rather than copied, pointer equality should be
1419  * a sufficient test.)
1420  */
1421  new_joininfo = list_append_unique_ptr(new_joininfo, rinfo);
1422  }
1423  }
1424 
1425  return new_joininfo;
1426 }
List * list_append_unique_ptr(List *list, void *datum)
Definition: list.c:1355
Relids required_relids
Definition: pathnodes.h:2560

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

1330 {
1331  ListCell *l;
1332 
1333  foreach(l, input_rel->joininfo)
1334  {
1335  RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
1336 
1337  if (bms_is_subset(rinfo->required_relids, joinrel->relids))
1338  {
1339  /*
1340  * This clause should become a restriction clause for the joinrel,
1341  * since it refers to no outside rels. However, if it's a clone
1342  * clause then it might be too late to evaluate it, so we have to
1343  * check. (If it is too late, just ignore the clause, taking it
1344  * on faith that another clone was or will be selected.) Clone
1345  * clauses should always be outer-join clauses, so we compare
1346  * against both_input_relids.
1347  */
1348  if (rinfo->has_clone || rinfo->is_clone)
1349  {
1350  Assert(!RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids));
1351  if (!bms_is_subset(rinfo->required_relids, both_input_relids))
1352  continue;
1353  if (bms_overlap(rinfo->incompatible_relids, both_input_relids))
1354  continue;
1355  }
1356  else
1357  {
1358  /*
1359  * For non-clone clauses, we just Assert it's OK. These might
1360  * be either join or filter clauses; if it's a join clause
1361  * then it should not refer to the current join's output.
1362  * (There is little point in checking incompatible_relids,
1363  * because it'll be NULL.)
1364  */
1365  Assert(RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids) ||
1367  both_input_relids));
1368  }
1369 
1370  /*
1371  * OK, so add it to the list, being careful to eliminate
1372  * duplicates. (Since RestrictInfo nodes in different joinlists
1373  * will have been multiply-linked rather than copied, pointer
1374  * equality should be a sufficient test.)
1375  */
1376  new_restrictlist = list_append_unique_ptr(new_restrictlist, rinfo);
1377  }
1378  else
1379  {
1380  /*
1381  * This clause is still a join clause at this level, so we ignore
1382  * it in this routine.
1383  */
1384  }
1385  }
1386 
1387  return new_restrictlist;
1388 }
Relids incompatible_relids
Definition: pathnodes.h:2563
bool has_clone
Definition: pathnodes.h:2541

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().