You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sedona.apache.org by ji...@apache.org on 2026/10/13 07:30:26 UTC

(sedona) branch master updated: [GH-3453] Return NULL from Snowflake ST_Distance and ST_HausdorffDistance for empty geometries (#3454)

This is an automated email from the ASF dual-hosted git repository.

jiayuasu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sedona.git


The following commit(s) were added to refs/heads/master by this push:
     new 3464ffd8b7f [GH-3453] Return NULL from Snowflake ST_Distance and ST_HausdorffDistance for empty geometries (#3454)
3464ffd8b7f is described below

commit 3464ffd8b7f3f1bd2a545d69113141abae65a8cd
Author: Jia Yu <ji...@apache.org>
AuthorDate: Tue Oct 13 00:30:19 2026 -0700

    [GH-3453] Return NULL from Snowflake ST_Distance and ST_HausdorffDistance for empty geometries (#3454)
---
 .../api/flink/Measurement-Functions/ST_Distance.md |  2 +
 .../Measurement-Functions/ST_HausdorffDistance.md  |  2 +-
 .../Measurement-Functions/ST_Distance.md           |  2 +
 .../Measurement-Functions/ST_HausdorffDistance.md  |  2 +-
 docs/api/sql/Measurement-Functions/ST_Distance.md  |  2 +
 .../Measurement-Functions/ST_HausdorffDistance.md  |  2 +-
 .../sedona/snowflake/snowsql/TestFunctions.java    |  6 +++
 .../org/apache/sedona/snowflake/snowsql/UDFs.java  |  6 +--
 .../apache/sedona/snowflake/snowsql/UDFsV2.java    |  6 +--
 .../snowsql/EmptyGeometryDistanceTest.java         | 60 ++++++++++++++++++++++
 10 files changed, 81 insertions(+), 9 deletions(-)

diff --git a/docs/api/flink/Measurement-Functions/ST_Distance.md b/docs/api/flink/Measurement-Functions/ST_Distance.md
index e5bf0d1782d..aea4599b43a 100644
--- a/docs/api/flink/Measurement-Functions/ST_Distance.md
+++ b/docs/api/flink/Measurement-Functions/ST_Distance.md
@@ -21,6 +21,8 @@
 
 Introduction: Return the Euclidean distance between A and B
 
+If either geometry is empty, the function returns `NULL`.
+
 ![ST_Distance](../../../image/ST_Distance/ST_Distance.svg "ST_Distance")
 
 Format: `ST_Distance (A: Geometry, B: Geometry)`
diff --git a/docs/api/flink/Measurement-Functions/ST_HausdorffDistance.md b/docs/api/flink/Measurement-Functions/ST_HausdorffDistance.md
index 49cbcd6227d..81ae767d5b7 100644
--- a/docs/api/flink/Measurement-Functions/ST_HausdorffDistance.md
+++ b/docs/api/flink/Measurement-Functions/ST_HausdorffDistance.md
@@ -25,7 +25,7 @@ Each segment is broken down into equal-length subsegments whose ratio with segme
 
 Hence, the lower the densityFrac value, the more accurate is the computed hausdorff distance, and the more time it takes to compute it.
 
-If any of the geometry is empty, 0.0 is returned.
+If either geometry is empty, the function returns `NULL`.
 
 !!!Note
     Accepted range of densityFrac is (0.0, 1.0], if any other value is provided, ST_HausdorffDistance throws an IllegalArgumentException
diff --git a/docs/api/snowflake/vector-data/Measurement-Functions/ST_Distance.md b/docs/api/snowflake/vector-data/Measurement-Functions/ST_Distance.md
index c2163b61358..17938b50b21 100644
--- a/docs/api/snowflake/vector-data/Measurement-Functions/ST_Distance.md
+++ b/docs/api/snowflake/vector-data/Measurement-Functions/ST_Distance.md
@@ -21,6 +21,8 @@
 
 Introduction: Return the Euclidean distance between A and B
 
+If either geometry is empty, the function returns `NULL`.
+
 ![ST_Distance](../../../../image/ST_Distance/ST_Distance.svg "ST_Distance")
 
 Format: `ST_Distance (A:geometry, B:geometry)`
diff --git a/docs/api/snowflake/vector-data/Measurement-Functions/ST_HausdorffDistance.md b/docs/api/snowflake/vector-data/Measurement-Functions/ST_HausdorffDistance.md
index 4382efc4bc0..cb04577d541 100644
--- a/docs/api/snowflake/vector-data/Measurement-Functions/ST_HausdorffDistance.md
+++ b/docs/api/snowflake/vector-data/Measurement-Functions/ST_HausdorffDistance.md
@@ -25,7 +25,7 @@ Each segment is broken down into equal-length subsegments whose ratio with segme
 
 Hence, the lower the densityFrac value, the more accurate is the computed hausdorff distance, and the more time it takes to compute it.
 
-If any of the geometry is empty, 0.0 is returned.
+If either geometry is empty, the function returns `NULL`.
 
 !!!Note
     Accepted range of densityFrac is (0.0, 1.0], if any other value is provided, ST_HausdorffDistance throws an IllegalArgumentException
diff --git a/docs/api/sql/Measurement-Functions/ST_Distance.md b/docs/api/sql/Measurement-Functions/ST_Distance.md
index fc039b1620a..dcbf5327fbb 100644
--- a/docs/api/sql/Measurement-Functions/ST_Distance.md
+++ b/docs/api/sql/Measurement-Functions/ST_Distance.md
@@ -21,6 +21,8 @@
 
 Introduction: Return the Euclidean distance between A and B
 
+If either geometry is empty, the function returns `NULL`.
+
 ![ST_Distance](../../../image/ST_Distance/ST_Distance.svg "ST_Distance")
 
 Format: `ST_Distance (A: Geometry, B: Geometry)`
diff --git a/docs/api/sql/Measurement-Functions/ST_HausdorffDistance.md b/docs/api/sql/Measurement-Functions/ST_HausdorffDistance.md
index cdd93038a79..a8bfb9d8d1d 100644
--- a/docs/api/sql/Measurement-Functions/ST_HausdorffDistance.md
+++ b/docs/api/sql/Measurement-Functions/ST_HausdorffDistance.md
@@ -25,7 +25,7 @@ Each segment is broken down into equal-length subsegments whose ratio with segme
 
 Hence, the lower the densityFrac value, the more accurate is the computed hausdorff distance, and the more time it takes to compute it.
 
-If any of the geometry is empty, 0.0 is returned.
+If either geometry is empty, the function returns `NULL`.
 
 !!!Note
     Accepted range of densityFrac is (0.0, 1.0], if any other value is provided, ST_HausdorffDistance throws an IllegalArgumentException
diff --git a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java
index 140f58e6d86..94c5e5228ef 100644
--- a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java
+++ b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java
@@ -365,6 +365,9 @@ public class TestFunctions extends TestBase {
     verifySqlSingleRes(
         "select sedona.ST_Distance(sedona.ST_GeomFromText('POINT(1 2)'), sedona.ST_GeomFromText('POINT(3 2)'))",
         2.0);
+    verifySqlSingleRes(
+        "select sedona.ST_Distance(sedona.ST_GeomFromText('POINT(1 2)'), sedona.ST_GeomFromText('POLYGON EMPTY'))",
+        null);
   }
 
   @Test
@@ -511,6 +514,9 @@ public class TestFunctions extends TestBase {
     verifySqlSingleRes(
         "select sedona.ST_HausdorffDistance(sedona.ST_GeomFromText('LINESTRING(0 0, 1 1, 2 2)'), sedona.ST_GeomFromText('LINESTRING(0 0, 1 1, 3 3)'))",
         1.4142135623730951);
+    verifySqlSingleRes(
+        "select sedona.ST_HausdorffDistance(sedona.ST_GeomFromText('LINESTRING(0 0, 1 1, 2 2)'), sedona.ST_GeomFromText('POLYGON EMPTY'))",
+        null);
   }
 
   @Test
diff --git a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java
index ba5a12f263d..7995c42e273 100644
--- a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java
+++ b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java
@@ -348,7 +348,7 @@ public class UDFs {
   }
 
   @UDFAnnotations.ParamMeta(argNames = {"left", "right"})
-  public static double ST_Distance(byte[] left, byte[] right) {
+  public static Double ST_Distance(byte[] left, byte[] right) {
     return Functions.distance(GeometrySerde.deserialize(left), GeometrySerde.deserialize(right));
   }
 
@@ -542,13 +542,13 @@ public class UDFs {
   }
 
   @UDFAnnotations.ParamMeta(argNames = {"geom1", "geom2"})
-  public static double ST_HausdorffDistance(byte[] geom1, byte[] geom2) {
+  public static Double ST_HausdorffDistance(byte[] geom1, byte[] geom2) {
     return Functions.hausdorffDistance(
         GeometrySerde.deserialize(geom1), GeometrySerde.deserialize(geom2));
   }
 
   @UDFAnnotations.ParamMeta(argNames = {"geom1", "geom2", "densifyFrac"})
-  public static double ST_HausdorffDistance(byte[] geom1, byte[] geom2, double densifyFrac) {
+  public static Double ST_HausdorffDistance(byte[] geom1, byte[] geom2, double densifyFrac) {
     return Functions.hausdorffDistance(
         GeometrySerde.deserialize(geom1), GeometrySerde.deserialize(geom2), densifyFrac);
   }
diff --git a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java
index 7b843a74357..5b692eab41c 100644
--- a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java
+++ b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java
@@ -482,7 +482,7 @@ public class UDFsV2 {
   @UDFAnnotations.ParamMeta(
       argNames = {"left", "right"},
       argTypes = {"Geometry", "Geometry"})
-  public static double ST_Distance(String left, String right) {
+  public static Double ST_Distance(String left, String right) {
     return Functions.distance(GeometrySerde.deserGeoJson(left), GeometrySerde.deserGeoJson(right));
   }
 
@@ -681,7 +681,7 @@ public class UDFsV2 {
   @UDFAnnotations.ParamMeta(
       argNames = {"geom1", "geom2"},
       argTypes = {"Geometry", "Geometry"})
-  public static double ST_HausdorffDistance(String geom1, String geom2) {
+  public static Double ST_HausdorffDistance(String geom1, String geom2) {
     return Functions.hausdorffDistance(
         GeometrySerde.deserGeoJson(geom1), GeometrySerde.deserGeoJson(geom2));
   }
@@ -689,7 +689,7 @@ public class UDFsV2 {
   @UDFAnnotations.ParamMeta(
       argNames = {"geom1", "geom2", "densifyFrac"},
       argTypes = {"Geometry", "Geometry", "double"})
-  public static double ST_HausdorffDistance(String geom1, String geom2, double densifyFrac) {
+  public static Double ST_HausdorffDistance(String geom1, String geom2, double densifyFrac) {
     return Functions.hausdorffDistance(
         GeometrySerde.deserGeoJson(geom1), GeometrySerde.deserGeoJson(geom2), densifyFrac);
   }
diff --git a/snowflake/src/test/java/org/apache/sedona/snowflake/snowsql/EmptyGeometryDistanceTest.java b/snowflake/src/test/java/org/apache/sedona/snowflake/snowsql/EmptyGeometryDistanceTest.java
new file mode 100644
index 00000000000..c0637fb3f08
--- /dev/null
+++ b/snowflake/src/test/java/org/apache/sedona/snowflake/snowsql/EmptyGeometryDistanceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sedona.snowflake.snowsql;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.apache.sedona.common.Constructors;
+import org.junit.Test;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.io.ParseException;
+
+/** Distance UDFs return NULL for an empty geometry, as the Spark and Flink functions do. */
+public class EmptyGeometryDistanceTest {
+
+  @Test
+  public void distanceToAnEmptyGeometryIsNull() throws ParseException {
+    Geometry line = Constructors.geomFromWKT("LINESTRING (0 0, 1 1, 2 2)", 0);
+    Geometry other = Constructors.geomFromWKT("LINESTRING (0 0, 1 1, 3 3)", 0);
+    Geometry empty = Constructors.geomFromWKT("POLYGON EMPTY", 0);
+
+    byte[] lineWkb = GeometrySerde.serialize(line);
+    byte[] emptyWkb = GeometrySerde.serialize(empty);
+    assertNull(UDFs.ST_Distance(lineWkb, emptyWkb));
+    assertNull(UDFs.ST_Distance(emptyWkb, lineWkb));
+    assertNull(UDFs.ST_HausdorffDistance(lineWkb, emptyWkb));
+    assertNull(UDFs.ST_HausdorffDistance(lineWkb, emptyWkb, 0.5));
+    assertEquals(
+        1.4142135623730951,
+        UDFs.ST_HausdorffDistance(lineWkb, GeometrySerde.serialize(other)),
+        1e-12);
+
+    String lineJson = GeometrySerde.serGeoJson(line);
+    String emptyJson = GeometrySerde.serGeoJson(empty);
+    assertNull(UDFsV2.ST_Distance(lineJson, emptyJson));
+    assertNull(UDFsV2.ST_Distance(emptyJson, lineJson));
+    assertNull(UDFsV2.ST_HausdorffDistance(lineJson, emptyJson));
+    assertNull(UDFsV2.ST_HausdorffDistance(lineJson, emptyJson, 0.5));
+    assertEquals(
+        1.4142135623730951,
+        UDFsV2.ST_HausdorffDistance(lineJson, GeometrySerde.serGeoJson(other)),
+        1e-12);
+  }
+}