- SpecialJoinInfo *match_sjinfo;
- bool reversed;
- bool unique_ified;
- bool is_valid_inner;
- ListCell *l;
-
- /*
- * Ensure output params are set on failure return. This is just to
- * suppress uninitialized-variable warnings from overly anal compilers.
- */
- *sjinfo_p = NULL;
- *reversed_p = false;
-
- /*
- * If we have any special joins, the proposed join might be illegal; and
- * in any case we have to determine its join type. Scan the join info
- * list for conflicts.
- */
- match_sjinfo = NULL;
- reversed = false;
- unique_ified = false;
- is_valid_inner = true;
-
- foreach(l, root->join_info_list)
- {
- SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
-
- /*
- * This special join is not relevant unless its RHS overlaps the
- * proposed join. (Check this first as a fast path for dismissing
- * most irrelevant SJs quickly.)
- */
- if (!bms_overlap(sjinfo->min_righthand, joinrelids))
- continue;
-
- /*
- * Also, not relevant if proposed join is fully contained within RHS
- * (ie, we're still building up the RHS).
- */
- if (bms_is_subset(joinrelids, sjinfo->min_righthand))
- continue;
-
- /*
- * Also, not relevant if SJ is already done within either input.
- */
- if (bms_is_subset(sjinfo->min_lefthand, rel1->relids) &&
- bms_is_subset(sjinfo->min_righthand, rel1->relids))
- continue;
- if (bms_is_subset(sjinfo->min_lefthand, rel2->relids) &&
- bms_is_subset(sjinfo->min_righthand, rel2->relids))
- continue;
-
- /*
- * If it's a semijoin and we already joined the RHS to any other rels
- * within either input, then we must have unique-ified the RHS at that
- * point (see below). Therefore the semijoin is no longer relevant in
- * this join path.
- */
- if (sjinfo->jointype == JOIN_SEMI)
- {
- if (bms_is_subset(sjinfo->syn_righthand, rel1->relids) &&
- !bms_equal(sjinfo->syn_righthand, rel1->relids))
- continue;
- if (bms_is_subset(sjinfo->syn_righthand, rel2->relids) &&
- !bms_equal(sjinfo->syn_righthand, rel2->relids))
- continue;
- }
-
- /*
- * If one input contains min_lefthand and the other contains
- * min_righthand, then we can perform the SJ at this join.
- *
- * Barf if we get matches to more than one SJ (is that possible?)
- */
- if (bms_is_subset(sjinfo->min_lefthand, rel1->relids) &&
- bms_is_subset(sjinfo->min_righthand, rel2->relids))
- {
- if (match_sjinfo)
- return false; /* invalid join path */
- match_sjinfo = sjinfo;
- reversed = false;
- }
- else if (bms_is_subset(sjinfo->min_lefthand, rel2->relids) &&
- bms_is_subset(sjinfo->min_righthand, rel1->relids))
- {
- if (match_sjinfo)
- return false; /* invalid join path */
- match_sjinfo = sjinfo;
- reversed = true;
- }
- else if (sjinfo->jointype == JOIN_SEMI &&
- bms_equal(sjinfo->syn_righthand, rel2->relids) &&
- create_unique_path(root, rel2, rel2->cheapest_total_path,
- sjinfo) != NULL)
- {
- /*----------
- * For a semijoin, we can join the RHS to anything else by
- * unique-ifying the RHS (if the RHS can be unique-ified).
- * We will only get here if we have the full RHS but less
- * than min_lefthand on the LHS.
- *
- * The reason to consider such a join path is exemplified by
- * SELECT ... FROM a,b WHERE (a.x,b.y) IN (SELECT c1,c2 FROM c)
- * If we insist on doing this as a semijoin we will first have
- * to form the cartesian product of A*B. But if we unique-ify
- * C then the semijoin becomes a plain innerjoin and we can join
- * in any order, eg C to A and then to B. When C is much smaller
- * than A and B this can be a huge win. So we allow C to be
- * joined to just A or just B here, and then make_join_rel has
- * to handle the case properly.
- *
- * Note that actually we'll allow unique-ified C to be joined to
- * some other relation D here, too. That is legal, if usually not
- * very sane, and this routine is only concerned with legality not
- * with whether the join is good strategy.
- *----------
- */
- if (match_sjinfo)
- return false; /* invalid join path */
- match_sjinfo = sjinfo;
- reversed = false;
- unique_ified = true;
- }
- else if (sjinfo->jointype == JOIN_SEMI &&
- bms_equal(sjinfo->syn_righthand, rel1->relids) &&
- create_unique_path(root, rel1, rel1->cheapest_total_path,
- sjinfo) != NULL)
- {
- /* Reversed semijoin case */
- if (match_sjinfo)
- return false; /* invalid join path */
- match_sjinfo = sjinfo;
- reversed = true;
- unique_ified = true;
- }
- else
- {
- /*----------
- * Otherwise, the proposed join overlaps the RHS but isn't
- * a valid implementation of this SJ. It might still be
- * a legal join, however. If both inputs overlap the RHS,
- * assume that it's OK. Since the inputs presumably got past
- * this function's checks previously, they can't overlap the
- * LHS and their violations of the RHS boundary must represent
- * SJs that have been determined to commute with this one.
- * We have to allow this to work correctly in cases like
- * (a LEFT JOIN (b JOIN (c LEFT JOIN d)))
- * when the c/d join has been determined to commute with the join
- * to a, and hence d is not part of min_righthand for the upper
- * join. It should be legal to join b to c/d but this will appear
- * as a violation of the upper join's RHS.
- * Furthermore, if one input overlaps the RHS and the other does
- * not, we should still allow the join if it is a valid
- * implementation of some other SJ. We have to allow this to
- * support the associative identity
- * (a LJ b on Pab) LJ c ON Pbc = a LJ (b LJ c ON Pbc) on Pab
- * since joining B directly to C violates the lower SJ's RHS.
- * We assume that make_outerjoininfo() set things up correctly
- * so that we'll only match to some SJ if the join is valid.
- * Set flag here to check at bottom of loop.
- *----------
- */
- if (sjinfo->jointype != JOIN_SEMI &&
- bms_overlap(rel1->relids, sjinfo->min_righthand) &&
- bms_overlap(rel2->relids, sjinfo->min_righthand))
- {
- /* seems OK */
- Assert(!bms_overlap(joinrelids, sjinfo->min_lefthand));
- }
- else
- is_valid_inner = false;
- }
- }
-
- /*
- * Fail if violated some SJ's RHS and didn't match to another SJ. However,
- * "matching" to a semijoin we are implementing by unique-ification
- * doesn't count (think: it's really an inner join).
- */
- if (!is_valid_inner &&
- (match_sjinfo == NULL || unique_ified))
- return false; /* invalid join path */
-
- /* Otherwise, it's a valid join */
- *sjinfo_p = match_sjinfo;
- *reversed_p = reversed;
- return true;