docs: private void generateOuterAccessPaths(BranchNode parentNode) {
          JoinNode outerChildNode = parentNode.getLeftNode();
          assert(outerChildNode != null);
          JoinType joinType = parentNode.getJoinType();
          // For LEFT and FULL join types, the outer join expressions are kept as a pre-join predicate
          // at the join node to pre-qualify the outer rows
          List<AbstractExpression> joinOuterList =  (joinType == JoinType.INNER) ?
                  parentNode.m_joinOuterList : null;
          if (outerChildNode instanceof BranchNode) {
              generateOuterAccessPaths((BranchNode)outerChildNode);
              generateInnerAccessPaths((BranchNode)outerChildNode);
              // The join node can have only sequential scan access
              outerChildNode.m_accessPaths.add(getRelevantNaivePath(joinOuterList,
                      parentNode.m_whereOuterList));
              assert(outerChildNode.m_accessPaths.size() > 0);
              return;
          }
          // WHERE Outer expressions must stay at the join node for the FULL joins
          // They will be added later as part of the WHERE predicate of the join node
          List<AbstractExpression> parentWhereList = null;
          if (joinType != JoinType.FULL) {
              parentWhereList = parentNode.m_whereOuterList;
          }
          outerChildNode.m_accessPaths.addAll(
                  getRelevantAccessPathsForTable(outerChildNode.getTableScan(),
                          joinOuterList, parentWhereList, null));
      }