code: public List<JoinNode> extractSubTrees() {
          List<JoinNode> subTrees = new ArrayList<>();
          // Extract the first sub-tree starting at the root
          subTrees.add(this);
  
          List<JoinNode> leafNodes = new ArrayList<>();
          extractSubTree(leafNodes);
          // Continue with the leafs
          for (JoinNode leaf : leafNodes) {
              subTrees.addAll(leaf.extractSubTrees());
          }
          return subTrees;
      }
docs: Split a join tree into one or more sub-trees. Each sub-tree has the same join type
  for all join nodes. The root of the child tree in the parent tree is replaced with a 'dummy' node
  which id is negated id of the child root node.
  @param tree - The join tree
  @return the list of sub-trees from the input tree