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 ee50c951fe [common] Fix map equality for binary keys (#8536)
ee50c951fe is described below

commit ee50c951fe18dc757ea5aa7fb16c19bc5c372ed4
Author: Eunbin Son <[email protected]>
AuthorDate: Mon Jul 13 11:38:31 2026 +0900

    [common] Fix map equality for binary keys (#8536)
    
    Fix `InternalRowUtils.equals` for `MAP<BINARY, ...>` keys by comparing
    map keys through typed equality instead of Java `Map.containsKey`.
---
 .../org/apache/paimon/utils/InternalRowUtils.java  | 49 ++++++++++++++++++--
 .../apache/paimon/utils/InternalRowUtilsTest.java  | 54 ++++++++++++++++++++++
 2 files changed, 98 insertions(+), 5 deletions(-)

diff --git 
a/paimon-common/src/main/java/org/apache/paimon/utils/InternalRowUtils.java 
b/paimon-common/src/main/java/org/apache/paimon/utils/InternalRowUtils.java
index 668d1d21a0..1ff433f3e2 100644
--- a/paimon-common/src/main/java/org/apache/paimon/utils/InternalRowUtils.java
+++ b/paimon-common/src/main/java/org/apache/paimon/utils/InternalRowUtils.java
@@ -109,10 +109,20 @@ public class InternalRowUtils {
                                     mapType.getValueType());
                 }
                 InternalArray keyArray1 = map1.keyArray();
+                InternalArray keyArray2 = map2.keyArray();
+                InternalArray valueArray1 = map1.valueArray();
+                InternalArray valueArray2 = map2.valueArray();
+                boolean[] matched = new boolean[map2.size()];
                 for (int i = 0; i < map1.size(); i++) {
-                    Object key = get(keyArray1, i, mapType.getKeyType());
-                    if (!map2.contains(key)
-                            || !equals(map1.get(key), map2.get(key), 
mapType.getValueType())) {
+                    if (!hasEqualMapEntry(
+                            keyArray1,
+                            valueArray1,
+                            i,
+                            keyArray2,
+                            valueArray2,
+                            matched,
+                            mapType.getKeyType(),
+                            mapType.getValueType())) {
                         return false;
                     }
                 }
@@ -137,6 +147,33 @@ public class InternalRowUtils {
         return true;
     }
 
+    private static boolean hasEqualMapEntry(
+            InternalArray keyArray1,
+            InternalArray valueArray1,
+            int pos1,
+            InternalArray keyArray2,
+            InternalArray valueArray2,
+            boolean[] matched,
+            DataType keyType,
+            DataType valueType) {
+        Object key1 = get(keyArray1, pos1, keyType);
+        Object value1 = get(valueArray1, pos1, valueType);
+        for (int j = 0; j < keyArray2.size(); j++) {
+            if (matched[j]) {
+                continue;
+            }
+            Object key2 = get(keyArray2, j, keyType);
+            if (equals(key1, key2, keyType)) {
+                Object value2 = get(valueArray2, j, valueType);
+                if (equals(value1, value2, valueType)) {
+                    matched[j] = true;
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     public static int hash(Object data, DataType dataType) {
         if (data == null) {
             return 0;
@@ -167,10 +204,12 @@ public class InternalRowUtils {
                                 (InternalMap) data, mapType.getKeyType(), 
mapType.getValueType());
             }
             InternalArray keyArray = map.keyArray();
+            InternalArray valueArray = map.valueArray();
             for (int i = 0; i < map.size(); i++) {
                 Object key = get(keyArray, i, mapType.getKeyType());
-                result = 37 * result + hash(key, mapType.getKeyType());
-                result = 37 * result + hash(map.get(key), 
mapType.getValueType());
+                Object value = get(valueArray, i, mapType.getValueType());
+                result +=
+                        37 * hash(key, mapType.getKeyType()) + hash(value, 
mapType.getValueType());
             }
         } else if (data instanceof byte[]) {
             result = Arrays.hashCode((byte[]) data);
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/utils/InternalRowUtilsTest.java 
b/paimon-common/src/test/java/org/apache/paimon/utils/InternalRowUtilsTest.java
index 821d52a540..c085147c41 100644
--- 
a/paimon-common/src/test/java/org/apache/paimon/utils/InternalRowUtilsTest.java
+++ 
b/paimon-common/src/test/java/org/apache/paimon/utils/InternalRowUtilsTest.java
@@ -197,6 +197,60 @@ public class InternalRowUtilsTest {
                 .isEqualTo(InternalRowUtils.hash(row2, rowType));
     }
 
+    @Test
+    public void testEqualsMapWithBinaryKeys() {
+        Map<byte[], Integer> map1 = new HashMap<>();
+        map1.put(new byte[] {1, 2}, 1);
+        map1.put(new byte[] {3, 4}, 2);
+        Map<byte[], Integer> map2 = new HashMap<>();
+        map2.put(new byte[] {3, 4}, 2);
+        map2.put(new byte[] {1, 2}, 1);
+
+        assertThat(
+                        InternalRowUtils.equals(
+                                new GenericMap(map1),
+                                new GenericMap(map2),
+                                DataTypes.MAP(DataTypes.BINARY(2), 
DataTypes.INT())))
+                .isTrue();
+        assertThat(
+                        InternalRowUtils.hash(
+                                new GenericMap(map1),
+                                DataTypes.MAP(DataTypes.BINARY(2), 
DataTypes.INT())))
+                .isEqualTo(
+                        InternalRowUtils.hash(
+                                new GenericMap(map2),
+                                DataTypes.MAP(DataTypes.BINARY(2), 
DataTypes.INT())));
+
+        Map<byte[], Integer> map3 = new HashMap<>();
+        map3.put(new byte[] {1, 3}, 1);
+        map3.put(new byte[] {3, 4}, 2);
+        assertThat(
+                        InternalRowUtils.equals(
+                                new GenericMap(map1),
+                                new GenericMap(map3),
+                                DataTypes.MAP(DataTypes.BINARY(2), 
DataTypes.INT())))
+                .isFalse();
+
+        Map<byte[], Integer> map4 = new HashMap<>();
+        map4.put(new byte[] {1, 2}, 1);
+        map4.put(new byte[] {1, 2}, 2);
+        Map<byte[], Integer> map5 = new HashMap<>();
+        map5.put(new byte[] {1, 2}, 1);
+        map5.put(new byte[] {1, 3}, 2);
+        assertThat(
+                        InternalRowUtils.equals(
+                                new GenericMap(map4),
+                                new GenericMap(map5),
+                                DataTypes.MAP(DataTypes.BINARY(2), 
DataTypes.INT())))
+                .isFalse();
+        assertThat(
+                        InternalRowUtils.equals(
+                                new GenericMap(map5),
+                                new GenericMap(map4),
+                                DataTypes.MAP(DataTypes.BINARY(2), 
DataTypes.INT())))
+                .isFalse();
+    }
+
     @Test
     public void testCopyVector() {
         RowType rowType =

Reply via email to