Hi Michael,  actually I met NPE in my test. I think this code in `SparkEquiInnerJoin` will be executed in ExecuteBackend.

    val rightWithKeys = right.execute().mapPartitions { iter =>
      val generateRightKeys = new Projection(rightKeys, right.output)
      iter.map(row => (generateRightKeys(row), row.copy()))
    }

As `right.output` is needed when when running mapPartitions, so this `right` will be serialized to ExecuteBackend, which may introduce the error I mentioned before.