@SqlNullable
    @Description("Returns the vertex of a linestring at the specified index (indices started with 1) ")
    @ScalarFunction("ST_PointN")
    @SqlType(GEOMETRY_TYPE_NAME)
    public static Slice stPointN(@SqlType(GEOMETRY_TYPE_NAME) Slice input, @SqlType(INTEGER) long index)
    {
        Geometry geometry = deserialize(input);
        validateType("ST_PointN", geometry, EnumSet.of(LINE_STRING));

        LineString linestring = (LineString) geometry;
        if (index < 1 || index > linestring.getNumPoints()) {
            return null;
        }
        return serialize(linestring.getPointN(toIntExact(index) - 1));
    }
@Test
    public void testSTPointN()
    {
        assertPointN("LINESTRING(1 2, 3 4, 5 6, 7 8)", 1, "POINT (1 2)");
        assertPointN("LINESTRING(1 2, 3 4, 5 6, 7 8)", 3, "POINT (5 6)");
        assertPointN("LINESTRING(1 2, 3 4, 5 6, 7 8)", 10, null);
        assertPointN("LINESTRING(1 2, 3 4, 5 6, 7 8)", 0, null);
        assertPointN("LINESTRING(1 2, 3 4, 5 6, 7 8)", -1, null);

        assertInvalidPointN("POINT (1 2)", "POINT");
        assertInvalidPointN("MULTIPOINT (1 1, 2 2)", "MULTI_POINT");
        assertInvalidPointN("MULTILINESTRING ((1 1, 2 2), (3 3, 4 4))", "MULTI_LINE_STRING");
        assertInvalidPointN("POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))", "POLYGON");
        assertInvalidPointN("MULTIPOLYGON (((1 1, 1 4, 4 4, 4 1, 1 1)), ((1 1, 1 4, 4 4, 4 1, 1 1)))", "MULTI_POLYGON");
        assertInvalidPointN("GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6, 7 10))", "GEOMETRY_COLLECTION");
    }