presto-main/src/main/java/io/prestosql/sql/planner/plan/SpatialJoinNode.java/SpatialJoinNode/SpatialJoinNode
class SpatialJoinNode:    @JsonCreator
    public SpatialJoinNode(
            @JsonProperty("id") PlanNodeId id,
            @JsonProperty("type") Type type,
            @JsonProperty("left") PlanNode left,
            @JsonProperty("right") PlanNode right,
            @JsonProperty("outputSymbols") List<Symbol> outputSymbols,
            @JsonProperty("filter") Expression filter,
            @JsonProperty("leftPartitionSymbol") Optional<Symbol> leftPartitionSymbol,
            @JsonProperty("rightPartitionSymbol") Optional<Symbol> rightPartitionSymbol,
            @JsonProperty("kdbTree") Optional<String> kdbTree)
    {
        super(id);

        this.type = requireNonNull(type, "type is null");
        this.left = requireNonNull(left, "left is null");
        this.right = requireNonNull(right, "right is null");
        this.outputSymbols = ImmutableList.copyOf(requireNonNull(outputSymbols, "outputSymbols is null"));
        this.filter = requireNonNull(filter, "filter is null");
        this.leftPartitionSymbol = requireNonNull(leftPartitionSymbol, "leftPartitionSymbol is null");
        this.rightPartitionSymbol = requireNonNull(rightPartitionSymbol, "rightPartitionSymbol is null");
        this.kdbTree = requireNonNull(kdbTree, "kdbTree is null");

        Set<Symbol> inputSymbols = ImmutableSet.<Symbol>builder()
                .addAll(left.getOutputSymbols())
                .addAll(right.getOutputSymbols())
                .build();

        checkArgument(inputSymbols.containsAll(outputSymbols), "Left and right join inputs do not contain all output symbols");
        if (kdbTree.isPresent()) {
            checkArgument(leftPartitionSymbol.isPresent(), "Left partition symbol is missing");
            checkArgument(rightPartitionSymbol.isPresent(), "Right partition symbol is missing");
            checkArgument(left.getOutputSymbols().contains(leftPartitionSymbol.get()), "Left side of join does not contain left partition symbol");
            checkArgument(right.getOutputSymbols().contains(rightPartitionSymbol.get()), "Right side of join does not contain right partition symbol");
            this.distributionType = DistributionType.PARTITIONED;
        }
        else {
            checkArgument(!leftPartitionSymbol.isPresent(), "Left partition symbol is missing");
            checkArgument(!rightPartitionSymbol.isPresent(), "Right partition symbol is missing");
            this.distributionType = DistributionType.REPLICATED;
        }
    }