I thought about the strategy below in the past few days, and think it
is better because it uses less cycles to get the same answer. IIUC, the
related structs should be created during / after deconstruct_jointree rather
than join_search_xx stage.
The schemes I've been toying with tend to look more like putting a
PlaceHolderVar-ish wrapper around the Var or expression that represents
the below-the-join value. The wrapper node could carry any join ID
info that we find necessary.
Just to confirm my understanding, the wrapper node should answer some
questions like this.
/*
* rel_is_nullable_side
*
* For the given join ID joinrelids, return if the relid is in the nullable
* side.
*/
static bool
rel_is_nullable_side(PlannerInfo *root, Relids joinrelids, Index relid)
{
Assert(bms_is_member(relid, joinrelids));
...
}
The thing that I'm kind of stalled on is
how to define this struct so that it's not a big headache for join
strength reduction (which could remove the need for a wrapper altogether)
or outer-join reordering (which makes it a bit harder to define which
join we think is the one nulling the value).
I think about the outer-join reorder case, can we just rely on
SpecialJoinInfo.min_lefthands & min_righthands to get the answer?
The attached patch is based on that. and I did some test in the patch
as well, looks the answer is correct.
What's more, if the above is correct and the calls of rel_is_nullable_side
is small, do we still need think about more effective data struct?
Thanks!