From c44c47a773bd9073012935a29b0264d95920412c Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 14 Mar 2017 18:20:17 -0400 Subject: Some preliminary refactoring towards partitionwise join. Partitionwise join proposes add a concept of child join relations, which will have the same relationship with join relations as "other member" relations do with base relations. These relations will need some but not all of the handling that we currently have for join relations, and some but not all of the handling that we currently have for appendrels, since they are a mix of the two. Refactor a little bit so that the necessary bits of logic are exposed as separate functions. Ashutosh Bapat, reviewed and tested by Rajkumar Raghuwanshi and by me. Discussion: http://postgr.es/m/CAFjFpRfqotRR6cM3sooBHMHEVdkFfAZ6PyYg4GRZsoMuW08HjQ@mail.gmail.com --- src/backend/optimizer/util/relnode.c | 142 ++++++++++++++++++++--------------- 1 file changed, 83 insertions(+), 59 deletions(-) (limited to 'src/backend/optimizer/util') 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); /* @@ -327,6 +330,82 @@ find_join_rel(PlannerInfo *root, Relids relids) return NULL; } +/* + * 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, @@ -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 -- cgit v1.2.3