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

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


The following commit(s) were added to refs/heads/master by this push:
     new 34e9b9f313 [codegen] Fix wrong sort order for float and double columns 
with nan (#8295)
34e9b9f313 is described below

commit 34e9b9f3134e03c7f295cdaf0f221d4ab5f00b99
Author: Arnav Balyan <[email protected]>
AuthorDate: Sat Jun 20 01:04:16 2026 -0700

    [codegen] Fix wrong sort order for float and double columns with nan (#8295)
---
 .../org/apache/paimon/codegen/GenerateUtils.scala  |  6 ++-
 .../apache/paimon/codegen/CodeGenUtilsTest.java    | 62 ++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git 
a/paimon-codegen/src/main/scala/org/apache/paimon/codegen/GenerateUtils.scala 
b/paimon-codegen/src/main/scala/org/apache/paimon/codegen/GenerateUtils.scala
index 967d58ad30..4ea0df464f 100644
--- 
a/paimon-codegen/src/main/scala/org/apache/paimon/codegen/GenerateUtils.scala
+++ 
b/paimon-codegen/src/main/scala/org/apache/paimon/codegen/GenerateUtils.scala
@@ -125,8 +125,12 @@ object GenerateUtils {
       val sortUtil =
         classOf[org.apache.paimon.utils.SortUtil].getCanonicalName
       s"$sortUtil.compareBinary($leftTerm, $rightTerm)"
-    case TINYINT | SMALLINT | INTEGER | BIGINT | FLOAT | DOUBLE | DATE | 
TIME_WITHOUT_TIME_ZONE =>
+    case TINYINT | SMALLINT | INTEGER | BIGINT | DATE | TIME_WITHOUT_TIME_ZONE 
=>
       s"($leftTerm > $rightTerm ? 1 : $leftTerm < $rightTerm ? -1 : 0)"
+    case FLOAT =>
+      s"java.lang.Float.compare($leftTerm, $rightTerm)"
+    case DOUBLE =>
+      s"java.lang.Double.compare($leftTerm, $rightTerm)"
     case ARRAY | VECTOR =>
       val elementType = t.getTypeRoot match {
         case ARRAY => t.asInstanceOf[ArrayType].getElementType
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/codegen/CodeGenUtilsTest.java 
b/paimon-core/src/test/java/org/apache/paimon/codegen/CodeGenUtilsTest.java
index b6cab84413..f557c58aac 100644
--- a/paimon-core/src/test/java/org/apache/paimon/codegen/CodeGenUtilsTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/codegen/CodeGenUtilsTest.java
@@ -25,7 +25,10 @@ import org.apache.paimon.types.RowType;
 
 import org.junit.jupiter.api.Test;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.function.Supplier;
 
 import static org.apache.paimon.codegen.CodeGenUtils.newNormalizedKeyComputer;
@@ -121,6 +124,65 @@ class CodeGenUtilsTest {
         assertThat(ascending.getClass()).isNotEqualTo(descending.getClass());
     }
 
+    @Test
+    public void testFloatingPointComparatorMatchesTotalOrder() {
+        RecordComparator doubleComparator =
+                newRecordComparator(Arrays.asList(DOUBLE()), new int[] {0});
+        double[] doubles = {
+            Double.NEGATIVE_INFINITY, -1.0d, -0.0d, 0.0d, 1.0d, 
Double.POSITIVE_INFINITY, Double.NaN
+        };
+        for (double a : doubles) {
+            for (double b : doubles) {
+                assertThat(sign(doubleComparator.compare(GenericRow.of(a), 
GenericRow.of(b))))
+                        .as("compare(%s, %s)", a, b)
+                        .isEqualTo(sign(Double.compare(a, b)));
+            }
+        }
+
+        RecordComparator floatComparator =
+                newRecordComparator(Arrays.asList(FLOAT()), new int[] {0});
+        float[] floats = {
+            Float.NEGATIVE_INFINITY, -1.0f, -0.0f, 0.0f, 1.0f, 
Float.POSITIVE_INFINITY, Float.NaN
+        };
+        for (float a : floats) {
+            for (float b : floats) {
+                assertThat(sign(floatComparator.compare(GenericRow.of(a), 
GenericRow.of(b))))
+                        .as("compare(%s, %s)", a, b)
+                        .isEqualTo(sign(Float.compare(a, b)));
+            }
+        }
+    }
+
+    private static int sign(int value) {
+        return Integer.compare(value, 0);
+    }
+
+    @Test
+    public void sortByDoubleColumnWithNaNProducesTotalOrder() {
+        RecordComparator scoreComparator =
+                newRecordComparator(Arrays.asList(DOUBLE()), new int[] {0});
+
+        List<InternalRow> batch = new ArrayList<>();
+        for (int i = 0; i < 60; i++) {
+            batch.add(GenericRow.of((double) ((i % 11) - 5)));
+            if (i % 4 == 0) {
+                batch.add(GenericRow.of(Double.NaN));
+            }
+        }
+        batch.add(GenericRow.of(Double.NEGATIVE_INFINITY));
+        batch.add(GenericRow.of(Double.POSITIVE_INFINITY));
+
+        Collections.sort(batch, scoreComparator);
+
+        for (int i = 1; i < batch.size(); i++) {
+            double prev = batch.get(i - 1).getDouble(0);
+            double cur = batch.get(i).getDouble(0);
+            assertThat(Double.compare(prev, cur))
+                    .as("position %d (%s) sorted after position %d (%s)", i - 
1, prev, i, cur)
+                    .isLessThanOrEqualTo(0);
+        }
+    }
+
     @Test
     public void testRecordEqualiserCodegenCache() {
         assertClassEquals(() -> newRecordEqualiser(Arrays.asList(STRING(), 
INT())));

Reply via email to