Skip to content

Commit f397d6d

Browse files
Copilotrobfrank
andauthored
#1534 Fix ClassCastException in BinaryComparator for TYPE_BINARY comparisons (#2762)
Co-authored-by: robfrank <413587+robfrank@users.noreply.github.com>
1 parent 26ebcf4 commit f397d6d

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

engine/src/main/java/com/arcadedb/serializer/BinaryComparator.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,21 @@ public int compare(final Object value1, final byte type1, final Object value2, f
289289
case BinaryTypes.TYPE_BINARY: {
290290
switch (type2) {
291291
case BinaryTypes.TYPE_BINARY: {
292-
return ((Binary) value1).compareTo((Binary) value2);
292+
// Handle both byte[] and Binary objects
293+
if (value1 instanceof byte[] bytes1) {
294+
if (value2 instanceof byte[] bytes2) {
295+
return UnsignedBytesComparator.BEST_COMPARATOR.compare(bytes1, bytes2);
296+
} else if (value2 instanceof Binary binary2) {
297+
return -compareBytes(binary2.getContent(), bytes1);
298+
}
299+
} else if (value1 instanceof Binary binary1) {
300+
if (value2 instanceof byte[] bytes2) {
301+
return compareBytes(binary1.getContent(), bytes2);
302+
} else if (value2 instanceof Binary binary2) {
303+
return binary1.compareTo(binary2);
304+
}
305+
}
306+
throw new IllegalArgumentException("Invalid binary type for comparison: " + value1.getClass() + " and " + value2.getClass());
293307
}
294308
}
295309
throw new UnsupportedOperationException("Comparing binary types");
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright © 2021-present Arcade Data Ltd (info@arcadedata.com)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-FileCopyrightText: 2021-present Arcade Data Ltd (info@arcadedata.com)
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package com.arcadedb.index;
20+
21+
import com.arcadedb.TestHelper;
22+
import com.arcadedb.database.Database;
23+
import com.arcadedb.schema.Schema;
24+
import com.arcadedb.schema.Type;
25+
import org.junit.jupiter.api.Test;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
import static org.assertj.core.api.Assertions.fail;
29+
30+
public class BinaryIndexTest extends TestHelper {
31+
32+
@Test
33+
public void testBinaryIndexInsertAndLookup() {
34+
database.transaction(() -> {
35+
if (database.getSchema().existsType("vt"))
36+
database.getSchema().dropType("vt");
37+
38+
database.getSchema()
39+
.getOrCreateVertexType("vt")
40+
.getOrCreateProperty("prop", Type.BINARY)
41+
.setMandatory(true)
42+
.setNotNull(true)
43+
.getOrCreateIndex(Schema.INDEX_TYPE.LSM_TREE, false);
44+
});
45+
46+
database.transaction(() -> {
47+
// First insert - SUCCESS
48+
database.newVertex("vt").set("prop", new byte[]{1, 2, 3}).save();
49+
});
50+
51+
database.transaction(() -> {
52+
// Lookup - should work
53+
try {
54+
final IndexCursor results = database.lookupByKey("vt", "prop", new byte[]{1, 2, 3});
55+
assertThat(results.hasNext()).as("Should find the inserted vertex").isTrue();
56+
} catch (Exception e) {
57+
fail("Lookup failed with exception", e);
58+
}
59+
});
60+
61+
database.transaction(() -> {
62+
// Second insert - should also work
63+
database.newVertex("vt").set("prop", new byte[]{1, 2, 3}).save();
64+
});
65+
66+
database.transaction(() -> {
67+
// Third insert - should also work
68+
database.newVertex("vt").set("prop", new byte[]{1, 2, 3}).save();
69+
});
70+
}
71+
72+
@Test
73+
public void testBinaryIndexAfterReopen() {
74+
database.transaction(() -> {
75+
if (database.getSchema().existsType("vt"))
76+
database.getSchema().dropType("vt");
77+
78+
database.getSchema()
79+
.getOrCreateVertexType("vt")
80+
.getOrCreateProperty("prop", Type.BINARY)
81+
.setMandatory(true)
82+
.setNotNull(true)
83+
.getOrCreateIndex(Schema.INDEX_TYPE.LSM_TREE, false);
84+
});
85+
86+
database.transaction(() -> {
87+
database.newVertex("vt").set("prop", new byte[]{1, 2, 3}).save();
88+
database.newVertex("vt").set("prop", new byte[]{4, 5, 6}).save();
89+
});
90+
91+
// Close and reopen the database
92+
database.close();
93+
database = factory.open();
94+
95+
database.transaction(() -> {
96+
// Should work after reopening
97+
try {
98+
database.newVertex("vt").set("prop", new byte[]{7, 8, 9}).save();
99+
} catch (Exception e) {
100+
fail("Failed to insert after reopen", e);
101+
}
102+
});
103+
104+
database.transaction(() -> {
105+
// Lookup should work
106+
try {
107+
final IndexCursor results = database.lookupByKey("vt", "prop", new byte[]{1, 2, 3});
108+
assertThat(results.hasNext()).as("Should find the vertex after reopen").isTrue();
109+
} catch (Exception e) {
110+
fail("Lookup failed after reopen", e);
111+
}
112+
});
113+
}
114+
}

0 commit comments

Comments
 (0)