Yup, it looks like that is the behaviour from JTS and GEOS. The problem is that your LINESTRING is invalid. If you have PostGIS 2.0, you can use ST_MakeValid(geometry) to fix the LINESTRING to a POINT.
This query verifies your bug, and uses ST_MakeValid as a workaround.
WITH data AS (SELECT 'POLYGON((150 280, 99 215, 190 210, 150 280))'::geometry AS poly,
'POINT(170 240)'::geometry AS pt)
SELECT ST_Intersects(poly, pt) AS intersects_poly_pt,
ST_Intersects(poly, ST_MakeLine(pt, pt)) AS intersects_poly_line,
ST_IsValid(ST_MakeLine(pt, pt)) AS isvalid_line,
ST_AsText(ST_MakeValid(ST_MakeLine(pt, pt))) AS valid_geom,
ST_Intersects(poly, ST_MakeValid(ST_MakeLine(pt, pt))) AS intersects_poly_valid_geom
FROM data;
with results (using psql's \x
option):
NOTICE: Too few points in geometry component at or near point 170 240
-[ RECORD 1 ]--------------+---------------
intersects_poly_pt | t
intersects_poly_line | f
isvalid_line | f
valid_geom | POINT(170 240)
intersects_poly_valid_geom | t
If you are using a previous version of PostGIS (pre 2.0), then you can cast from an invalid LINESTRING to a box2d, then back to a GEOMETRY. For a two-vertex LINESTRING with same coordinates, this turns into a POINT. Here is the PostGIS 1.5 version of the above:
WITH data AS (SELECT 'POLYGON((150 280, 99 215, 190 210, 150 280))'::geometry AS poly,
'LINESTRING(170 240, 170 240)'::geometry AS line)
SELECT ST_Intersects(poly, line) AS intersects_bad_line,
ST_IsValid(line) AS isvalid_line,
ST_AsText(CASE WHEN NOT ST_IsValid(line) THEN line::box2d::geometry
ELSE line END) as valid_geom,
ST_Intersects(poly, CASE WHEN NOT ST_IsValid(line) THEN line::box2d::geometry
ELSE line END) AS intersects_poly_valid_geom
FROM data;
with results:
NOTICE: Too few points in geometry component at or near point 170 240
NOTICE: Too few points in geometry component at or near point 170 240
NOTICE: Too few points in geometry component at or near point 170 240
-[ RECORD 1 ]--------------+---------------
intersects_bad_line | f
isvalid_line | f
valid_geom | POINT(170 240)
intersects_poly_valid_geom | t
I wouldn't expect any significant difference in performance unless you have very unusual data. There are a few places in the code where optimizations are put in for edge cases like two-point LineStrings, and you will miss out on some of these if you're storing your LineStrings as MultiLineStrings. There may be some special code paths in GEOS that you miss out on with MultiLineStrings as well.
There's a storage overhead to Multi* geometries, which will be small as long as the number of points in your geometry is small (really, it's only significant for single-point MultiPoints).
That said, if your geometries all have only a single component, there is no advantage to storing them as MultiLineStrings, so you may as well convert to LineString. If nothing else, this will make your data model more self-documenting.
Best Answer
As per the function documentation, ST_LineMerge will return a Linestring when each linestring in a MultiLinestring connects. If they do not, it'll return a MultiLinestring:
However, your error says the function is returning a GeometryCollection. As per the documentation, there are only two options when that occur:
This means your table either has a Polygon or a GeometryCollection data point (or many of them). To find out, you can do:
Then you can find which data points have these geometries by doing:
Afterwards, you can either fix these geometries or skip them in your processing.
UPDATE
Apparently, there are (at least) two other cases in which ST_LineMerge can also return a Geometry Collection, found by OP in the comments. These are if the geometry is empty or if it's invalid. I'll be condensing the information here for future reference.
The following mock-up query specifies the different possible returns for ST_LineMerge, as well as the original geometry and if it's valid and empty.
UPDATE 2
Some points about the above table:
As a further testing, ST_LineMerge accepts Z and M coordinates, although they don't behave well. The Z ordinal is not checked when evaluating if the linestrings touch (so MULTILINESTRINGZ((0 0 0, 1 1 1), (1 1 2, 2 2 2)) returns a merged Linestring, with the first Z value it finds). The M value is not considered and is dropped entirely.