There are two cases of joinTree:
  a leaf node, m_table != null
  a branch node, m_leftNode != null and m_rightNode != null.
I think that it is clearer to tell them apart by testing m_table != null (or == null) than by testing m_leftNode != null (or == null).
Once you have tested any of these conditions, you don't have to also test m_rightNode for null -- it is null iff m_leftNode is null iff m_table isn't null.

It seems like findJoinFilters all by itself does what analyseJoinTree does so analyseJoinTree is not required.
findJoinFilters is kind of a strange name because we usually think of join filters as being filters that reference two tables in a join but you are specifically looking for one-table filters on the mvTable.

But maybe analyzing the join tree is the wrong approach. Maybe the better approach is to wait and only analyze the mvTable scan node to find its actual predicate clauses and consider moving each of them to the reaggnode. I don't think that it will be that much more expensive to do it for each plan, and we could always fall back to doing it for the first plan and caching it for later plans because I suspect that it is going to be the same from plan to plan.