Bug #87075 ClusterJ ClusterJDatastoreException.getCode() returns 0 instead of 630
Submitted: 14 Jul 2017 16:52 Modified: 17 Jul 2017 17:28
Reporter: Michael Seydel Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Cluster: Cluster/J Severity:S2 (Serious)
Version:7.5.5 OS:MacOS (10.12.5)
Assigned to: CPU Architecture:Any
Tags: ClusterJ, ClusterJDatastoreException, constraint violation, duplicate value, getclassification, getcode, getmysqlcode, getstatus, jar, java, ndb

[14 Jul 2017 16:52] Michael Seydel
Description:
The com.mysql.clusterj.ClusterJDatastoreException.getCode() method (see: https://dev.mysql.com/doc/ndbapi/en/mccj-clusterj-clusterjdatastoreexception.html#mccj-clu...) should get the code for an error, as listed at https://dev.mysql.com/doc/ndbapi/en/ndb-error-codes-single.html

However, we find that when a 630 should result, we instead see a 0. The message string still contains the error code, and we are currently checking the substring as a workaround, but it's hacky and unreliable (e.g. the string contains that number for a different reaso).

Other getCode() results appear to work, in particular we tested 159 and 121. We find that the message strings look different in the work / not work cases; log entries from local testing:

ClusterJDatastoreException getCode => 241 for message => Error in NdbJTie: returnCode -1, code 241, mysqlCode 159, status 2, classification 4, message Invalid schema object version .
ClusterJDatastoreException getCode => 0 for message => Datastore exception. Return code: -1 Error code: 630 MySQL code: 121 Status: 2 Classification: 3 Message:  NdbRecordOperationImpl for table notification_metadata 
ClusterJDatastoreException getCode => 893 for message => Error in NdbJTie: returnCode -1, code 893, mysqlCode 121, status 2, classification 3, message Constraint violation e.g. duplicate value in unique index ndb_tiledb/def/user_identification/external_user_idx$unique.

Though it sometimes works, we're extremely hesitant to consider any of this at all reliable. We're stuck between using a method that we have observed not functioning correctly, doing string manipulation, or some combination thereof.

How to repeat:
We're using NDB database and Jar versions 7.5.5 and mysql:mysql-connector-java:6.0.6 (https://mvnrepository.com/artifact/mysql/mysql-connector-java/6.0.6).

Given a simple schema like:

CREATE TABLE example_table (
    mykey INT,
    PRIMARY KEY(mykey)
) engine=ndb;

and its ClusterJ annotated interface

@PersistenceCapable(table = "example_table")
public interface IExample {
    @PrimaryKey
    @Column(name = "mykey")
    int getMyKey();

    void setMyKey(int myKey);
}

one can run the following code:

// clusterJSession setup first
final IExample example = clusterJSession.newInstance(IExample.class);

example.setMyKey(1);

clusterJSession.persist(example);
clusterJSession.persist(example); // this will cause a constraint violation when committed

try {
    clusterJSession.flush();
} catch (ClusterJDatastoreException e) {
    System.out.println(String.format("---\ncode: %s | mysqlCode: %s | status: %s | classification: %s\nMessage:\n%s\n---",
            e.getCode(), e.getMysqlCode(), e.getStatus(), e.getClassification(), e.getMessage()));
}

and find that the first four getter methods that return ints all return 0 rather than the values they should, as are visible from the getMessage() call. In particular, I got the following output:

---
code: 0 | mysqlCode: 0 | status: 0 | classification: 0
Message:
Datastore exception. Return code: -1 Error code: 630 MySQL code: 121 Status: 2 Classification: 3 Message:  NdbRecordOperationImpl for table example_table 
Datastore exception. Return code: -1 Error code: 630 MySQL code: 121 Status: 2 Classification: 3 Message:  NdbRecordOperationImpl for table example_table 

---

but expected the first line to be "code: 630 | mysqlCode: 121 | status: 2 | classification: 3".

Thrown stack trace:
Caused by: com.mysql.clusterj.ClusterJDatastoreException: Datastore exception. Return code: -1 Error code: 630 MySQL code: 121 Status: 2 Classification: 3 Message:  NdbRecordOperationImpl for table example_table 
Datastore exception. Return code: -1 Error code: 630 MySQL code: 121 Status: 2 Classification: 3 Message:  NdbRecordOperationImpl for table example_table 

	at com.mysql.clusterj.tie.ClusterTransactionImpl.performPostExecuteCallbacks(ClusterTransactionImpl.java:590)
	at com.mysql.clusterj.tie.ClusterTransactionImpl.executeNoCommit(ClusterTransactionImpl.java:207)
	at com.mysql.clusterj.core.SessionImpl.executeNoCommit(SessionImpl.java:1498)
	at com.mysql.clusterj.core.SessionImpl.executeNoCommit(SessionImpl.java:1511)
	at com.mysql.clusterj.core.SessionImpl.flush(SessionImpl.java:1424)
	at com.mysql.clusterj.core.SessionImpl.flush(SessionImpl.java:1432)
	at com.example.Example.repro(Example.java:30)
	at com.example.Example.lambda$main$0(Example.java:16)

Suggested fix:
Remove the constructors:
ClusterJDatastoreException(String msg)
ClusterJDatastoreException(String msg, Throwable cause)
ClusterJDatastoreException(Throwable cause)

and make the relevant variables final so that they cannot accidentally not be initialized.
[17 Jul 2017 17:28] MySQL Verification Team
Hi,
Thanks for the submission. Verified as described.
all best
Bogdan