Skip to content

Fix ClassCastException in BinaryComparator for TYPE_BINARY comparisons#2762

Merged
robfrank merged 4 commits intomainfrom
copilot/fix-binary-index-issue
Nov 10, 2025
Merged

Fix ClassCastException in BinaryComparator for TYPE_BINARY comparisons#2762
robfrank merged 4 commits intomainfrom
copilot/fix-binary-index-issue

Conversation

Copy link
Contributor

Copilot AI commented Nov 7, 2025

What does this PR do?

Fixes a ClassCastException in BinaryComparator.compare() that occurs when comparing TYPE_BINARY values in LSM tree indexes. The comparator incorrectly assumed both operands are Binary objects, but deserialized values are byte[] arrays.

Motivation

Binary indexes break in two scenarios:

  1. Lookup operations fail with ClassCastException when comparing user-provided byte[] against indexed values
  2. Insert operations fail after database reopen because deserialized keys are byte[], not Binary objects

Example from issue:

db.newVertex("vt").set("prop", new byte[]{1,2,3}).save();  // SUCCESS
db.lookupByKey("vt", "prop", new byte[]{1,2,3});           // FAIL: ClassCastException

// After reopening database
db.newVertex("vt").set("prop", new byte[]{1,2,3}).save();  // FAIL: ClassCastException

Related issues

Fixes issue: Binary index is broken.

Additional Notes

Changes:

  • BinaryComparator.java: Handle all combinations of byte[] and Binary objects in TYPE_BINARY comparisons
    • byte[] vs byte[]UnsignedBytesComparator
    • byte[] vs Binary → compare via Binary's content array
    • Binary vs byte[] → compare via Binary's content array
    • Binary vs Binary → existing Binary.compareTo()
  • BinaryIndexTest.java: Test cases for insert, lookup, and database reopen scenarios

Root cause: TYPE_BINARY values are serialized as either byte[] or Binary, always deserialized as byte[], but comparison logic only handled Binary objects.

Checklist

  • I have run the build using mvn clean package command
  • My unit tests cover both failure and success scenarios

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • esm.ubuntu.com
    • Triggering command: /usr/lib/apt/methods/https (dns block)
  • repository.apache.org
    • Triggering command: /usr/lib/jvm/java-21-openjdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.11/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.11/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.11 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.11/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/arcadedb/arcadedb org.codehaus.plexus.classworlds.launcher.Launcher clean compile -DskipTests (dns block)
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java -classpath /home/REDACTED/.m2/wrapper/dists/apache-maven-3.9.9/3477a4f1/boot/plexus-classworlds-2.8.0.jar -Dclassworlds.conf=/home/REDACTED/.m2/wrapper/dists/apache-maven-3.9.9/3477a4f1/bin/m2.conf -Dmaven.home=/home/REDACTED/.m2/wrapper/dists/apache-maven-3.9.9/3477a4f1 -Dlibrary.jansi.path=/home/REDACTED/.m2/wrapper/dists/apache-maven-3.9.9/3477a4f1/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/arcadedb/arcadedb org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip -DskipTests -Dmaven.test.skip.exec -Dlicense.skip=true -Drat.skip=true -Dspotless.check.skip=true -s /home/REDACTED/work/arcadedb/.codeql-scratch/dbs/java/working/settings.xml com.github.ferstl:depgraph-maven-plugin:4.0.3-CodeQL:graph -B -DclasspathScopes=compile -DoutputDirectory=/home/REDACTED/work/arcadedb/.codeql-scratch/dbs/java/working/java-standalone-dependency-graph11621566166271152122/${project.groupId}/${project.artifactId} -DgraphFormat=json -Dmaven.ext.class.path=/opt/hostedtoolcache/CodeQL/2.23.3/x64/codeql/java/tools/java-buildless-maven-plugin.jar (dns block)
  • scarf.sh
    • Triggering command: node ./report.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Binary index is broken.</issue_title>
<issue_description>### ArcadeDB Version:

ArcadeDB Server v24.2.1 (build ce2658d/1710272693676/main)

OS and JDK Version:

Same results on three JDK Versions

Mac OS X 14.0 - OpenJDK 64-Bit Server VM 21.0.2 (Homebrew)
Mac OS X 14.0 - OpenJDK 64-Bit Server VM 17.0.9 (GraalVM CE 17.0.9+9.1)
Mac OS X 14.0 - OpenJDK 64-Bit Server VM 11.0.22 (Corretto-11.0.22.7.1)

Problems

Adding a Binary index breaks other code.

I suspect that it is because the cast to Binary in BinaryComparator is not working properly.

Steps to reproduce

Simple demo code

import com.arcadedb.ContextConfiguration;
import com.arcadedb.schema.Schema;
import com.arcadedb.schema.Type;
import com.arcadedb.server.ArcadeDBServer;

public class Main {
    public static void main(String[] args) {
        var s = new ArcadeDBServer(new ContextConfiguration());

        s.start();

        var db = s.getOrCreateDatabase("db");

        if(db.getSchema().existsType("vt"))
            db.getSchema().dropType("vt");

        db.getSchema()
                .getOrCreateVertexType("vt")
                .getOrCreateProperty("prop", Type.BINARY)
                .setMandatory(true)
                .setNotNull(true)
                .getOrCreateIndex(Schema.INDEX_TYPE.LSM_TREE, false);

        // SUCCESS
        db.newVertex("vt").set("prop", new byte[]{1,2,3}).save();

        // FAIL
        try{
            db.lookupByKey("vt", "prop", new byte[]{1,2,3});
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        // SUCCESS
        db.newVertex("vt").set("prop", new byte[]{1,2,3}).save();
        // SUCCESS
        db.newVertex("vt").set("prop", new byte[]{1,2,3}).save();

        // reopening database
        s.stop();
        s.start();
        db = s.getOrCreateDatabase("db");

        // FAIL
        try{
            db.newVertex("vt").set("prop", new byte[]{1, 2, 3}).save();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 3 commits November 7, 2025 22:29
Co-authored-by: robfrank <413587+robfrank@users.noreply.github.com>
Co-authored-by: robfrank <413587+robfrank@users.noreply.github.com>
Co-authored-by: robfrank <413587+robfrank@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix broken binary index implementation Fix ClassCastException in BinaryComparator for TYPE_BINARY comparisons Nov 7, 2025
Copilot AI requested a review from robfrank November 7, 2025 22:47
@robfrank robfrank requested a review from lvca November 9, 2025 12:55
@mergify
Copy link
Contributor

mergify bot commented Nov 9, 2025

🧪 CI Insights

Here's what we observed from your CI run for 3af475a.

🟢 All jobs passed!

But CI Insights is watching 👀

@codacy-production
Copy link

codacy-production bot commented Nov 9, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.09% 27.27%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (fcb51e0) 73233 46651 63.70%
Head commit (3af475a) 73243 (+10) 46726 (+75) 63.80% (+0.09%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#2762) 11 3 27.27%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

@robfrank robfrank marked this pull request as ready for review November 10, 2025 09:08
@robfrank robfrank merged commit f397d6d into main Nov 10, 2025
30 of 33 checks passed
@robfrank robfrank deleted the copilot/fix-binary-index-issue branch November 10, 2025 09:08
robfrank added a commit that referenced this pull request Feb 11, 2026
…arisons (#2762)

Co-authored-by: robfrank <413587+robfrank@users.noreply.github.com>
(cherry picked from commit f397d6d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Binary index is broken.

3 participants