ElidedNode **elidedrealouter, ElidedNode **elidedrealinner)
{
PlannedStmt *pstmt = context->pstmt;
+ JoinType jointype = ((Join *) plan)->jointype;
Plan *outerplan = plan->lefttree;
Plan *innerplan = plan->righttree;
ElidedNode *elidedouter;
elidedinner = pgpa_descend_node(pstmt, &innerplan);
/*
- * If we descended through a unique node, make a note that the identified
- * inner or outer subplan should be treated as a query plan feature when
- * the main tree traversal reaches it. (We could designate the Agg or
- * Unique node itself as the feature, but there shouldn't be any
- * RTI-bearing nodes between that node and this one.)
+ * If this is a semijoin that was converted to an inner join by making
+ * one side or the other unique, make a note that the inner or outer
+ * subplan, as appropriate, should be treated as a query plan feature
+ * when the main tree traversal reaches it.
+ *
+ * Conversely, if the planner could have made one side of the join unique
+ * and thereby converted it to an inner join, and chose not to do so,
+ * that is also worth noting. (XXX: I'm not sure that we need to emit
+ * non-unique advice in every case where these join-type tests pass.)
+ *
+ * NB: This code could appear slightly higher up in in this function,
+ * but none of the nodes through which we just descended should be have
+ * associated RTIs.
+ *
+ * NB: This seems like a somewhat hacky way of passing information up
+ * to the main tree walk, but I don't currently have a better idea.
*/
if (uniqueouter)
- pgpa_add_future_feature(context, PGPAQF_SJ_UNIQUE, outerplan);
+ pgpa_add_future_feature(context, PGPAQF_SEMIJOIN_UNIQUE, outerplan);
+ else if (jointype == JOIN_RIGHT_SEMI)
+ pgpa_add_future_feature(context, PGPAQF_SEMIJOIN_NON_UNIQUE, outerplan);
if (uniqueinner)
- pgpa_add_future_feature(context, PGPAQF_SJ_UNIQUE, innerplan);
+ pgpa_add_future_feature(context, PGPAQF_SEMIJOIN_UNIQUE, innerplan);
+ else if (jointype == JOIN_SEMI)
+ pgpa_add_future_feature(context, PGPAQF_SEMIJOIN_NON_UNIQUE, innerplan);
/* Set output parameters. */
*realouter = outerplan;
case PGPAQF_GATHER_MERGE:
appendStringInfo(buf, "GATHER_MERGE(");
break;
- case PGPAQF_SJ_UNIQUE:
- appendStringInfo(buf, "SJ_UNIQUE(");
+ case PGPAQF_SEMIJOIN_NON_UNIQUE:
+ appendStringInfo(buf, "SEMIJOIN_NON_UNIQUE(");
+ break;
+ case PGPAQF_SEMIJOIN_UNIQUE:
+ appendStringInfo(buf, "SEMIJOIN_UNIQUE(");
break;
}
pgpa_output_relations(&context, buf, qf->relids);
* For example, Gather nodes, desiginated by PGPAQF_GATHER, and Gather Merge
* nodes, designated by PGPAQF_GATHER_MERGE, are query features, because we'll
* want to admit some kind of advice that describes the portion of the plan
- * tree that appears beneath those nodes. Whenever we decide to implement a
- * semijoin by making one side unique and then performing a normal join, we
- * create a feature of PGPAQF_SG_UNIQUE, so that we can describe what RTIs need
- * to be made unique to perform the join. XXX We should also probably emit
- * advice for the decision NOT to unique-ify a semijoin.
+ * tree that appears beneath those nodes.
+ *
+ * Each semijoin can be implemented either by directly performing a semijoin,
+ * or by making one side unique and then performing a normal join. Either way,
+ * we use a query feature to notice what decision was made, so that we can
+ * describe it by enumerating the RTIs on that side of the join.
*
* To elaborate on the "no admixture of parent and child RTIs" rule, in all of
* these cases, if the entirety of an inheritance hierarchy appears beneath
{
PGPAQF_GATHER,
PGPAQF_GATHER_MERGE,
- PGPAQF_SJ_UNIQUE
+ PGPAQF_SEMIJOIN_NON_UNIQUE,
+ PGPAQF_SEMIJOIN_UNIQUE
} pgpa_qf_type;
/*