PostGIS: Stop trying to be helpful

We will be using PostGIS 2.0.

Part 1. In which a line of length 0 is demoted to a point.

Enter a linestring with the same start- as endpoint (a loop).

=> select st_astext(
    st_geomfromtext('LINESTRING(1 0, 2 0, 1 0)'));
------------
LINESTRING(1 0,2 0,1 0)

st_simplify reduces it to a linestring of length 0. It does not turn it into a point. So far so good.

=> select st_astext(
    st_simplify(
        st_geomfromtext('LINESTRING(1 0, 2 0, 1 0)'),
        100));
------------
LINESTRING(1 0,1 0)

st_line_substring however thinks it knows better.

=> select st_astext(
    st_line_substring(
        st_geomfromtext('LINESTRING(1 0, 1 0)'),
        0,
        1));
------------
POINT(1 0)

st_line_substring also thinks it should return a point when startfraction equals endfraction on a regular linestring.

=> select st_astext(
    st_line_substring(
        st_geomfromtext('LINESTRING(1 0, 2 0)'),
        0,
        0));
------------
POINT(1 0)

This is wrong. Don’t change the dimensions of my geometries without my explicit consent. If I want a point, I’ll use st_startpoint, st_endpoint, st_line_interpolate_point or some other function that returns a point. st_line_substring should return a linestring. Always. Especially, since a mixed collection of points and linestrings is treated differently from a collection of only linestrings.

Part 2. The point is not a line.

When st_collect receives two linestrings it returns a multilinestring.

=> select st_astext(
    st_collect(
        st_geomfromtext('LINESTRING(1 0, 2 0, 1 0)'),
        st_geomfromtext('LINESTRING(1 0, 3 0)')));
------------
MULTILINESTRING((1 0,2 0,1 0),(1 0,3 0))

But when it receives a point and a linestring, instead of throwing an error, it decides to return a geometrycollection.

=> select st_astext(
    st_collect(
        st_geomfromtext('POINT(1 0)'),
        st_geomfromtext('LINESTRING(1 0, 3 0)')));
------------
GEOMETRYCOLLECTION(POINT(1 0),LINESTRING(1 0,3 0))

Although this behavior is documented, it’s still wrong. This should be two different functions. One that only accepts geometries of the same type and returns a multi_* of that type (and errors if the types are different). And one that accepts geometries of any type and always returns a geometrycollection. Stop this function-overloading-on-return-type madness. Especially since subsequent operations can depend on this return type.

Part 3. There is no point.

st_linemerge is a useful function to merge a multilinestring.

=> select st_astext(
    st_linemerge(
        st_geomfromtext(
            'MULTILINESTRING((1 0, 2 0), (2 0, 3 0))')));
------------
LINESTRING(1 0,2 0,3 0)

The documentation says:

“Only use with multilinestring/linestrings. If you feed a polygon or geometrycollection into this function, it will return an empty geometrycollection”

Not so.

=> select st_astext(
    st_linemerge(
        st_geomfromtext(
            'GEOMETRYCOLLECTION(
                LINESTRING(1 0, 2 0),
                POINT(27 42),
                LINESTRING(2 0, 3 0))')));
------------
LINESTRING(1 0,2 0,3 0)

It happily accepts a geometrycollection and ignores any points that it contains.

Maybe all of this this can be convenient, maybe this sort of works most of the time, maybe this what other people want, but I want an error dammit. This stuff takes forever to debug.

Postgis: Stop trying to be helpful, stop hiding my bugs.

Posted on December 15, 2013