diff options
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 52 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinrels.c | 28 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 142 |
3 files changed, 149 insertions, 73 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 4db1d16c790..43bfd23804c 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -129,6 +129,8 @@ static void subquery_push_qual(Query *subquery, static void recurse_push_qual(Node *setOp, Query *topquery, RangeTblEntry *rte, Index rti, Node *qual); static void remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel); +static void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, + List *live_childrels); /* @@ -1182,19 +1184,11 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, { int parentRTindex = rti; List *live_childrels = NIL; - List *subpaths = NIL; - bool subpaths_valid = true; - List *partial_subpaths = NIL; - bool partial_subpaths_valid = true; - List *all_child_pathkeys = NIL; - List *all_child_outers = NIL; ListCell *l; /* * Generate access paths for each member relation, and remember the - * cheapest path for each one. Also, identify all pathkeys (orderings) - * and parameterizations (required_outer sets) available for the member - * relations. + * non-dummy children. */ foreach(l, root->append_rel_list) { @@ -1202,7 +1196,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, int childRTindex; RangeTblEntry *childRTE; RelOptInfo *childrel; - ListCell *lcp; /* append_rel_list contains all append rels; ignore others */ if (appinfo->parent_relid != parentRTindex) @@ -1237,6 +1230,45 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, * Child is live, so add it to the live_childrels list for use below. */ live_childrels = lappend(live_childrels, childrel); + } + + /* Add paths to the "append" relation. */ + add_paths_to_append_rel(root, rel, live_childrels); +} + + +/* + * add_paths_to_append_rel + * Generate paths for given "append" relation given the set of non-dummy + * child rels. + * + * The function collects all parameterizations and orderings supported by the + * non-dummy children. For every such parameterization or ordering, it creates + * an append path collecting one path from each non-dummy child with given + * parameterization or ordering. Similarly it collects partial paths from + * non-dummy children to create partial append paths. + */ +static void +add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, + List *live_childrels) +{ + List *subpaths = NIL; + bool subpaths_valid = true; + List *partial_subpaths = NIL; + bool partial_subpaths_valid = true; + List *all_child_pathkeys = NIL; + List *all_child_outers = NIL; + ListCell *l; + + /* + * For every non-dummy child, remember the cheapest path. Also, identify + * all pathkeys (orderings) and parameterizations (required_outer sets) + * available for the non-dummy member relations. + */ + foreach(l, live_childrels) + { + RelOptInfo *childrel = lfirst(l); + ListCell *lcp; /* * If child has an unparameterized cheapest-total path, add that to diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 0d0068360c1..05516689765 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -32,6 +32,9 @@ static bool is_dummy_rel(RelOptInfo *rel); static void mark_dummy_rel(RelOptInfo *rel); static bool restriction_is_constant_false(List *restrictlist, bool only_pushed_down); +static void populate_joinrel_with_paths(PlannerInfo *root, RelOptInfo *rel1, + RelOptInfo *rel2, RelOptInfo *joinrel, + SpecialJoinInfo *sjinfo, List *restrictlist); /* @@ -724,6 +727,27 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) return joinrel; } + /* Add paths to the join relation. */ + populate_joinrel_with_paths(root, rel1, rel2, joinrel, sjinfo, + restrictlist); + + bms_free(joinrelids); + + return joinrel; +} + +/* + * populate_joinrel_with_paths + * Add paths to the given joinrel for given pair of joining relations. The + * SpecialJoinInfo provides details about the join and the restrictlist + * contains the join clauses and the other clauses applicable for given pair + * of the joining relations. + */ +static void +populate_joinrel_with_paths(PlannerInfo *root, RelOptInfo *rel1, + RelOptInfo *rel2, RelOptInfo *joinrel, + SpecialJoinInfo *sjinfo, List *restrictlist) +{ /* * Consider paths using each rel as both outer and inner. Depending on * the join type, a provably empty outer or inner rel might mean the join @@ -868,10 +892,6 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) elog(ERROR, "unrecognized join type: %d", (int) sjinfo->jointype); break; } - - bms_free(joinrelids); - - return joinrel; } diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index caf8291e106..6ab78545c36 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -49,6 +49,9 @@ static List *subbuild_joinrel_restrictlist(RelOptInfo *joinrel, static List *subbuild_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); /* @@ -328,6 +331,82 @@ find_join_rel(PlannerInfo *root, Relids relids) } /* + * set_foreign_rel_properties + * Set up foreign-join fields if outer and inner relation are foreign + * tables (or joins) belonging to the same server and assigned to the same + * user to check access permissions as. + * + * In addition to an exact match of userid, we allow the case where one side + * has zero userid (implying current user) and the other side has explicit + * userid that happens to equal the current user; but in that case, pushdown of + * the join is only valid for the current user. The useridiscurrent field + * records whether we had to make such an assumption for this join or any + * sub-join. + * + * Otherwise these fields are left invalid, so GetForeignJoinPaths will not be + * called for the join relation. + * + */ +static void +set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel, + RelOptInfo *inner_rel) +{ + if (OidIsValid(outer_rel->serverid) && + inner_rel->serverid == outer_rel->serverid) + { + if (inner_rel->userid == outer_rel->userid) + { + joinrel->serverid = outer_rel->serverid; + joinrel->userid = outer_rel->userid; + joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent; + joinrel->fdwroutine = outer_rel->fdwroutine; + } + else if (!OidIsValid(inner_rel->userid) && + outer_rel->userid == GetUserId()) + { + joinrel->serverid = outer_rel->serverid; + joinrel->userid = outer_rel->userid; + joinrel->useridiscurrent = true; + joinrel->fdwroutine = outer_rel->fdwroutine; + } + else if (!OidIsValid(outer_rel->userid) && + inner_rel->userid == GetUserId()) + { + joinrel->serverid = outer_rel->serverid; + joinrel->userid = inner_rel->userid; + joinrel->useridiscurrent = true; + joinrel->fdwroutine = outer_rel->fdwroutine; + } + } +} + +/* + * add_join_rel + * Add given join relation to the list of join relations in the given + * PlannerInfo. Also add it to the auxiliary hashtable if there is one. + */ +static void +add_join_rel(PlannerInfo *root, RelOptInfo *joinrel) +{ + /* GEQO requires us to append the new joinrel to the end of the list! */ + root->join_rel_list = lappend(root->join_rel_list, joinrel); + + /* store it into the auxiliary hashtable if there is one. */ + if (root->join_rel_hash) + { + JoinHashEntry *hentry; + bool found; + + hentry = (JoinHashEntry *) hash_search(root->join_rel_hash, + &(joinrel->relids), + HASH_ENTER, + &found); + Assert(!found); + hentry->join_rel = joinrel; + } +} + +/* * build_join_rel * Returns relation entry corresponding to the union of two given rels, * creating a new relation entry if none already exists. @@ -425,46 +504,8 @@ build_join_rel(PlannerInfo *root, joinrel->joininfo = NIL; joinrel->has_eclass_joins = false; - /* - * Set up foreign-join fields if outer and inner relation are foreign - * tables (or joins) belonging to the same server and assigned to the same - * user to check access permissions as. In addition to an exact match of - * userid, we allow the case where one side has zero userid (implying - * current user) and the other side has explicit userid that happens to - * equal the current user; but in that case, pushdown of the join is only - * valid for the current user. The useridiscurrent field records whether - * we had to make such an assumption for this join or any sub-join. - * - * Otherwise these fields are left invalid, so GetForeignJoinPaths will - * not be called for the join relation. - */ - if (OidIsValid(outer_rel->serverid) && - inner_rel->serverid == outer_rel->serverid) - { - if (inner_rel->userid == outer_rel->userid) - { - joinrel->serverid = outer_rel->serverid; - joinrel->userid = outer_rel->userid; - joinrel->useridiscurrent = outer_rel->useridiscurrent || inner_rel->useridiscurrent; - joinrel->fdwroutine = outer_rel->fdwroutine; - } - else if (!OidIsValid(inner_rel->userid) && - outer_rel->userid == GetUserId()) - { - joinrel->serverid = outer_rel->serverid; - joinrel->userid = outer_rel->userid; - joinrel->useridiscurrent = true; - joinrel->fdwroutine = outer_rel->fdwroutine; - } - else if (!OidIsValid(outer_rel->userid) && - inner_rel->userid == GetUserId()) - { - joinrel->serverid = outer_rel->serverid; - joinrel->userid = inner_rel->userid; - joinrel->useridiscurrent = true; - joinrel->fdwroutine = outer_rel->fdwroutine; - } - } + /* Compute information relevant to the foreign relations. */ + set_foreign_rel_properties(joinrel, outer_rel, inner_rel); /* * Create a new tlist containing just the vars that need to be output from @@ -532,25 +573,8 @@ build_join_rel(PlannerInfo *root, is_parallel_safe(root, (Node *) joinrel->reltarget->exprs)) joinrel->consider_parallel = true; - /* - * Add the joinrel to the query's joinrel list, and store it into the - * auxiliary hashtable if there is one. NB: GEQO requires us to append - * the new joinrel to the end of the list! - */ - root->join_rel_list = lappend(root->join_rel_list, joinrel); - - if (root->join_rel_hash) - { - JoinHashEntry *hentry; - bool found; - - hentry = (JoinHashEntry *) hash_search(root->join_rel_hash, - &(joinrel->relids), - HASH_ENTER, - &found); - Assert(!found); - hentry->join_rel = joinrel; - } + /* Add the joinrel to the PlannerInfo. */ + add_join_rel(root, joinrel); /* * Also, if dynamic-programming join search is active, add the new joinrel |