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 =