@ScalarFunction
    @SqlNullable
    @Description("Returns an array of spatial partition IDs for a given geometry")
    @SqlType("array(int)")
    public static Block spatialPartitions(@SqlType(KdbTreeType.NAME) Object kdbTree, @SqlType(GEOMETRY_TYPE_NAME) Slice geometry)
    {
        Envelope envelope = deserializeEnvelope(geometry);
        if (envelope.isEmpty()) {
            // Empty geometry
            return null;
        }

        return spatialPartitions((KdbTree) kdbTree, new Rectangle(envelope.getXMin(), envelope.getYMin(), envelope.getXMax(), envelope.getYMax()));
    }
@Test
    public void testSpatialPartitions()
    {
        String kdbTreeJson = makeKdbTreeJson();

        assertSpatialPartitions(kdbTreeJson, "POINT EMPTY", null);
        // points inside partitions
        assertSpatialPartitions(kdbTreeJson, "POINT (0 0)", ImmutableList.of(0));
        assertSpatialPartitions(kdbTreeJson, "POINT (3 1)", ImmutableList.of(1));
        // point on the border between two partitions
        assertSpatialPartitions(kdbTreeJson, "POINT (1 2.5)", ImmutableList.of(2));
        // point at the corner of three partitions
        assertSpatialPartitions(kdbTreeJson, "POINT (4.5 2.5)", ImmutableList.of(5));
        // points outside
        assertSpatialPartitions(kdbTreeJson, "POINT (-10 -10)", ImmutableList.of(0));
        assertSpatialPartitions(kdbTreeJson, "POINT (-10 10)", ImmutableList.of(2));
        assertSpatialPartitions(kdbTreeJson, "POINT (10 -10)", ImmutableList.of(4));
        assertSpatialPartitions(kdbTreeJson, "POINT (10 10)", ImmutableList.of(5));

        // geometry within a partition
        assertSpatialPartitions(kdbTreeJson, "MULTIPOINT (5 0.1, 6 2)", ImmutableList.of(3));
        // geometries spanning multiple partitions
        assertSpatialPartitions(kdbTreeJson, "MULTIPOINT (5 0.1, 5.5 3, 6 2)", ImmutableList.of(5, 3));
        assertSpatialPartitions(kdbTreeJson, "MULTIPOINT (3 2, 8 3)", ImmutableList.of(5, 4, 3, 2, 1));
        // geometry outside
        assertSpatialPartitions(kdbTreeJson, "MULTIPOINT (2 6, 5 7)", ImmutableList.of(5, 2));

        // with distance
        assertSpatialPartitions(kdbTreeJson, "POINT EMPTY", 1.2, null);
        assertSpatialPartitions(kdbTreeJson, "POINT (1 1)", 1.2, ImmutableList.of(0));
        assertSpatialPartitions(kdbTreeJson, "POINT (1 1)", 2.3, ImmutableList.of(2, 1, 0));
        assertSpatialPartitions(kdbTreeJson, "MULTIPOINT (5 0.1, 6 2)", 0.2, ImmutableList.of(3));
        assertSpatialPartitions(kdbTreeJson, "MULTIPOINT (5 0.1, 6 2)", 1.2, ImmutableList.of(5, 3, 2, 1));
        assertSpatialPartitions(kdbTreeJson, "MULTIPOINT (2 6, 3 7)", 1.2, ImmutableList.of(2));
    }