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 @@ -91,23 +91,12 @@ public static boolean equals(Object data1, Object data2, DataType dataType) {
return false;
}
MapType mapType = (MapType) dataType;
GenericMap map1;
GenericMap map2;
if (data1 instanceof GenericMap) {
map1 = (GenericMap) data1;
map2 = (GenericMap) data2;
} else {
map1 =
copyToGenericMap(
(InternalMap) data1,
mapType.getKeyType(),
mapType.getValueType());
map2 =
copyToGenericMap(
(InternalMap) data2,
mapType.getKeyType(),
mapType.getValueType());
}
// Decide per operand. One MapType is represented by GenericMap, BinaryMap or
// ColumnarMap interchangeably -- which is why the conversion below exists at all --
// so gating data2's cast on data1's concrete class threw ClassCastException
// whenever the two sides happened to use different representations.
GenericMap map1 = toGenericMap((InternalMap) data1, mapType);
GenericMap map2 = toGenericMap((InternalMap) data2, mapType);
InternalArray keyArray1 = map1.keyArray();
InternalArray keyArray2 = map2.keyArray();
InternalArray valueArray1 = map1.valueArray();
Expand Down Expand Up @@ -284,6 +273,12 @@ private static InternalMap copyMap(InternalMap map, DataType keyType, DataType v
return copyToGenericMap(map, keyType, valueType);
}

private static GenericMap toGenericMap(InternalMap map, MapType mapType) {
return map instanceof GenericMap
? (GenericMap) map
: copyToGenericMap(map, mapType.getKeyType(), mapType.getValueType());
}

private static GenericMap copyToGenericMap(
InternalMap map, DataType keyType, DataType valueType) {
Map<Object, Object> javaMap = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

package org.apache.paimon.utils;

import org.apache.paimon.data.BinaryArray;
import org.apache.paimon.data.BinaryArrayWriter;
import org.apache.paimon.data.BinaryMap;
import org.apache.paimon.data.BinaryRow;
import org.apache.paimon.data.BinaryString;
import org.apache.paimon.data.BinaryVector;
Expand All @@ -33,6 +36,7 @@
import org.apache.paimon.datagen.RandomGeneratorVisitor;
import org.apache.paimon.datagen.RowDataGenerator;
import org.apache.paimon.options.Options;
import org.apache.paimon.types.DataType;
import org.apache.paimon.types.DataTypeRoot;
import org.apache.paimon.types.DataTypes;
import org.apache.paimon.types.RowType;
Expand Down Expand Up @@ -299,4 +303,34 @@ public void testEqualsAndHashCodeNegativeCase() {
rowWithMap2.setField(0, new GenericMap(map2));
assertThat(InternalRowUtils.equals(rowWithMap1, rowWithMap2, rowType2)).isFalse();
}

@Test
public void testEqualsAcrossMapImplementations() {
DataType mapType = DataTypes.MAP(DataTypes.STRING(), DataTypes.INT());

Map<Object, Object> entries = new HashMap<>();
entries.put(BinaryString.fromString("a"), 1);
GenericMap generic = new GenericMap(entries);

BinaryArray keys = new BinaryArray();
BinaryArrayWriter keyWriter = new BinaryArrayWriter(keys, 1, 8);
keyWriter.writeString(0, BinaryString.fromString("a"));
keyWriter.complete();
BinaryArray values = new BinaryArray();
BinaryArrayWriter valueWriter = new BinaryArrayWriter(values, 1, 4);
valueWriter.writeInt(0, 1);
valueWriter.complete();
BinaryMap binary = BinaryMap.valueOf(keys, values);

// hash() already treats the two representations as interchangeable, so equals() throwing
// for one ordering is the inconsistency being fixed here.
assertThat(InternalRowUtils.hash(generic, mapType))
.isEqualTo(InternalRowUtils.hash(binary, mapType));

// Both orderings must agree. Only the generic-first one changes: it used to pick the
// GenericMap fast path off data1 and then cast data2 to GenericMap unconditionally,
// throwing ClassCastException for a BinaryMap.
assertThat(InternalRowUtils.equals(generic, binary, mapType)).isTrue();
assertThat(InternalRowUtils.equals(binary, generic, mapType)).isTrue();
}
}
Loading