Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ public static Double y(Geography g) {
* measurement functions. No CRS transformation or SRID compatibility check is performed; if the
* inputs have different SRIDs, the first input's SRID is used. When the second input is a
* LineString whose first coordinate equals the current endpoint, that seam coordinate is added
* only once. Point and MultiPoint coordinates are always retained.
* only once. Point and MultiPoint coordinates are always retained. Empty inputs contribute no
* coordinates; when exactly one coordinate remains, it is repeated to form a valid LineString.
*/
public static Geography makeLine(Geography g1, Geography g2) {
if (g1 == null || g2 == null) return null;
Expand Down Expand Up @@ -251,6 +252,11 @@ private static Geometry makeLineGeometry(Geometry first, Geometry second) {
coordinates.add(appended[i]);
}

// PostGIS and SedonaDB skip empty components. JTS cannot represent their one-coordinate
// LineString result, so repeat that coordinate while preserving the same point set.
if (coordinates.size() == 1) {
coordinates.add(new Coordinate(coordinates.get(0)));
}
return first.getFactory().createLineString(coordinates.toArray(new Coordinate[0]));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,33 @@ public void makeLine_coincidentPointsRemainUsableAfterWKBRoundTrip() throws Pars
assertEquals(3, Functions.nPoints(extended));
}

@Test
public void makeLine_skipsEmptyInputsAndNormalizesSingleCoordinate() throws ParseException {
Geography emptyPoint = Constructors.geogFromWKT("POINT EMPTY", 3857);
Geography emptyLine = Constructors.geogFromWKT("LINESTRING EMPTY", 4326);
Geography emptyMultiPoint = Constructors.geogFromWKT("MULTIPOINT EMPTY", 4326);
Geography point = Constructors.geogFromWKT("POINT (12 34)", 4326);

Geography onlySecond = roundTripWKB(Functions.makeLine(emptyPoint, point));
assertEquals("LINESTRING (12 34, 12 34)", Functions.asText(onlySecond));
assertEquals(2, Functions.nPoints(onlySecond));
assertEquals(3857, onlySecond.getSRID());

Geography onlyFirst = roundTripWKB(Functions.makeLine(point, emptyLine));
assertEquals("LINESTRING (12 34, 12 34)", Functions.asText(onlyFirst));
assertEquals(2, Functions.nPoints(onlyFirst));
assertEquals(4326, onlyFirst.getSRID());

Geography afterEmptyMultiPoint = roundTripWKB(Functions.makeLine(emptyMultiPoint, point));
assertEquals("LINESTRING (12 34, 12 34)", Functions.asText(afterEmptyMultiPoint));
assertEquals(2, Functions.nPoints(afterEmptyMultiPoint));

Geography noCoordinates = roundTripWKB(Functions.makeLine(emptyPoint, emptyLine));
assertEquals("LINESTRING EMPTY", Functions.asText(noCoordinates));
assertEquals(0, Functions.nPoints(noCoordinates));
assertEquals(3857, noCoordinates.getSRID());
}

@Test
public void makeLine_deduplicatesLineStringSeamAndPreservesOtherRepeats() throws ParseException {
Geography first = Constructors.geogFromWKT("LINESTRING (0 0, 1 0)", 4326);
Expand Down
2 changes: 1 addition & 1 deletion docs/api/flink/Geography-Functions/ST_MakeLine.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Return type: `Geography`

Since: `v1.9.1`

Only the two-argument signature accepts Geography inputs. The array form of `ST_MakeLine` remains Geometry-only. Repeated and coincident Point or MultiPoint coordinates are preserved. When the second input is a LineString whose first coordinate matches the current endpoint, that seam coordinate appears only once.
Only the two-argument signature accepts Geography inputs. The array form of `ST_MakeLine` remains Geometry-only. Repeated and coincident Point or MultiPoint coordinates are preserved. When the second input is a LineString whose first coordinate matches the current endpoint, that seam coordinate appears only once. Empty inputs contribute no coordinates. If exactly one coordinate remains, it is repeated to produce a valid LineString.

The output copies the first input's SRID without transforming either input or validating that their SRIDs match. If the inputs have different SRIDs, the second input's SRID is ignored. An SRID of `0` on the first input remains `0`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Return type: `Geography`

Since: `v1.9.1`

Only the two-argument signature accepts Geography inputs. The array/aggregate form of `ST_MakeLine` remains Geometry-only. Repeated and coincident Point or MultiPoint coordinates are preserved. When the second input is a LineString whose first coordinate matches the current endpoint, that seam coordinate appears only once.
Only the two-argument signature accepts Geography inputs. The array/aggregate form of `ST_MakeLine` remains Geometry-only. Repeated and coincident Point or MultiPoint coordinates are preserved. When the second input is a LineString whose first coordinate matches the current endpoint, that seam coordinate appears only once. Empty inputs contribute no coordinates. If exactly one coordinate remains, it is repeated to produce a valid LineString.

The output copies the first input's SRID without transforming either input or validating that their SRIDs match. If the inputs have different SRIDs, the second input's SRID is ignored. An SRID of `0` on the first input remains `0`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,27 @@ public void testMakeLinePreservesCoincidentPointsAndFirstSRID() throws Exception
}
}

@Test
public void testMakeLineSkipsEmptyGeographyInputs() throws Exception {
Table table =
tableEnv.sqlQuery(
"SELECT "
+ "ST_AsText(ST_MakeLine("
+ "ST_GeogFromWKT('POINT EMPTY', 3857), "
+ "ST_GeogFromWKT('POINT (12 34)', 4326))) AS empty_first, "
+ "ST_AsText(ST_MakeLine("
+ "ST_GeogFromWKT('POINT (12 34)', 4326), "
+ "ST_GeogFromWKT('LINESTRING EMPTY', 3857))) AS empty_second, "
+ "ST_AsEWKT(ST_MakeLine("
+ "ST_GeogFromWKT('POINT EMPTY', 3857), "
+ "ST_GeogFromWKT('LINESTRING EMPTY', 4326))) AS both_empty");

Row row = first(table);
assertEquals("LINESTRING (12 34, 12 34)", row.getFieldAs("empty_first"));
assertEquals("LINESTRING (12 34, 12 34)", row.getFieldAs("empty_second"));
assertEquals("SRID=3857; LINESTRING EMPTY", row.getFieldAs("both_empty"));
}

@Test
public void testDistance() throws Exception {
String wktA = "POINT (0 0)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,30 @@ class GeographyFunctionTest extends TestBaseScala {
assertEquals("SRID=4326; LINESTRING (0 0, 1 0, 2 0)", repeated.getString(1))
assertEquals(3, repeated.getInt(2))
}

it("ST_MakeLine skips empty geography inputs") {
val row = sparkSession
.sql("""
SELECT
ST_AsText(ST_MakeLine(
ST_GeogFromWKT('POINT EMPTY', 3857),
ST_GeogFromWKT('POINT (12 34)', 4326)
)) AS empty_first,
ST_AsText(ST_MakeLine(
ST_GeogFromWKT('POINT (12 34)', 4326),
ST_GeogFromWKT('LINESTRING EMPTY', 3857)
)) AS empty_second,
ST_AsEWKT(ST_MakeLine(
ST_GeogFromWKT('POINT EMPTY', 3857),
ST_GeogFromWKT('LINESTRING EMPTY', 4326)
)) AS both_empty
""")
.first()

assertEquals("LINESTRING (12 34, 12 34)", row.getString(0))
assertEquals("LINESTRING (12 34, 12 34)", row.getString(1))
assertEquals("SRID=3857; LINESTRING EMPTY", row.getString(2))
}
}

// ─── Level 2: ST_Length, ST_Area, ST_Distance ──────────────────────────
Expand Down
Loading