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);
/*
{
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)
{
int childRTindex;
RangeTblEntry *childRTE;
RelOptInfo *childrel;
- ListCell *lcp;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
* 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
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);
/*
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
elog(ERROR, "unrecognized join type: %d", (int) sjinfo->jointype);
break;
}
-
- bms_free(joinrelids);
-
- return 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);
/*
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,
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
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