Code review comment: Thanks for the review. Yeah that's the only bug that blocked this feature.

Code under review:
public void onMatch(RelOptRuleCall call) {
    LogicalCorrelate correlate = call.rel(0);
    RelNode outer = call.rel(1);
    RelNode uncollect = call.rel(2);

    if (correlate.getRequiredColumns().cardinality() != 1) {
      
      return;
    }
    if (correlate.getJoinType() != JoinRelType.INNER) {
      return;
    }

    if (!(uncollect instanceof ZetaSqlUnnest)) {
      
      uncollect = ((SingleRel) uncollect).getInput();
      if (uncollect instanceof RelSubset) {
        uncollect = ((RelSubset) uncollect).getOriginal();
      }
      if (!(uncollect instanceof ZetaSqlUnnest)) {
        return;
      }
    }

    RelNode project = ((ZetaSqlUnnest) uncollect).getInput();
    if (project instanceof RelSubset) {
      project = ((RelSubset) project).getOriginal();
    }
    if (!(project instanceof LogicalProject)) {
      return;
    }

    if (((LogicalProject) project).getProjects().size() != 1) {
      
      return;
    }

    RexNode exp = ((LogicalProject) project).getProjects().get(0);
    if (!(exp instanceof RexFieldAccess)) {
      return;
    }
    RexFieldAccess fieldAccess = (RexFieldAccess) exp;
    
    ImmutableList.Builder<Integer> fieldAccessIndices = ImmutableList.builder();
    while (true) {
      fieldAccessIndices.add(fieldAccess.getField().getIndex());
      if (!(fieldAccess.getReferenceExpr() instanceof RexFieldAccess)) {
        break;
      }
      fieldAccess = (RexFieldAccess) fieldAccess.getReferenceExpr();
    }

    call.transformTo(
        new BeamZetaSqlUnnestRel(
            correlate.getCluster(),
            correlate.getTraitSet().replace(BeamLogicalConvention.INSTANCE),
            convert(outer, outer.getTraitSet().replace(BeamLogicalConvention.INSTANCE)),
            call.rel(2).getRowType(),
            fieldAccessIndices.build()));
  }

Line commented on: if (correlate.getRequiredColumns().cardinality() != 1) {

Revised code:
public void onMatch(RelOptRuleCall call) {
    LogicalCorrelate correlate = call.rel(0);
    RelNode outer = call.rel(1);
    RelNode uncollect = call.rel(2);

    if (correlate.getRequiredColumns().cardinality() != 1) {
      
      return;
    }
    if (correlate.getJoinType() != JoinRelType.INNER) {
      return;
    }

    if (!(uncollect instanceof ZetaSqlUnnest)) {
      
      uncollect = ((SingleRel) uncollect).getInput();
      if (uncollect instanceof RelSubset) {
        uncollect = ((RelSubset) uncollect).getOriginal();
      }
      if (!(uncollect instanceof ZetaSqlUnnest)) {
        return;
      }
    }

    RelNode project = ((ZetaSqlUnnest) uncollect).getInput();
    if (project instanceof RelSubset) {
      project = ((RelSubset) project).getOriginal();
    }
    if (!(project instanceof LogicalProject)) {
      return;
    }

    if (((LogicalProject) project).getProjects().size() != 1) {
      
      return;
    }

    RexNode exp = ((LogicalProject) project).getProjects().get(0);
    if (!(exp instanceof RexFieldAccess)) {
      return;
    }
    RexFieldAccess fieldAccess = (RexFieldAccess) exp;
    
    ImmutableList.Builder<Integer> fieldAccessIndices = ImmutableList.builder();
    while (true) {
      fieldAccessIndices.add(fieldAccess.getField().getIndex());
      if (!(fieldAccess.getReferenceExpr() instanceof RexFieldAccess)) {
        break;
      }
      fieldAccess = (RexFieldAccess) fieldAccess.getReferenceExpr();
    }

    call.transformTo(
        new BeamZetaSqlUnnestRel(
            correlate.getCluster(),
            correlate.getTraitSet().replace(BeamLogicalConvention.INSTANCE),
            convert(outer, outer.getTraitSet().replace(BeamLogicalConvention.INSTANCE)),
            call.rel(2).getRowType(),
            fieldAccessIndices.build()));
  }