Bug #88596 ClusterJ NPE when querying table with "text" field by non-primary key
Submitted: 22 Nov 2017 1:01 Modified: 19 Feb 2019 10:50
Reporter: Michael Seydel Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Cluster: Cluster/J Severity:S2 (Serious)
Version:7.5.7 OS:MacOS
Assigned to: CPU Architecture:Any
Tags: ClusterJ, npe, NullPointerException, text

[22 Nov 2017 1:01] Michael Seydel
Description:
ClusterJ queries on any field other than the primary key result in a NullPointerException when a "text" field is present.

How to repeat:
Given the table definition

CREATE TABLE IF NOT EXISTS test (
    `identifier` BIGINT NOT NULL,
    payload TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,

    PRIMARY KEY(`identifier`) USING HASH
) engine=ndb
;

and model

@PersistenceCapable(table = "test")
public interface Test {

    @PrimaryKey
    @Column(name = "identifier")
    String getIdentifier();

    void setIdentifier(String identifier);

    @Column(name = "payload")
    String getPayload();

    void setPayload(String payload);
}

the query

final QueryBuilder builder = clusterJSession.getQueryBuilder();
final QueryDomainType<Test> domain = builder.createQueryDefinition(Test.class);
domain.where(domain.get("identifier").equal(domain.param("identifier")));

final Query<Test> query = clusterJSession.createQuery(domain);
query.setParameter("identifier", id);

return query.getResultList();

reliably results in a NullPointerException like so:

java.lang.NullPointerException
	at com.mysql.clusterj.tie.Utility.addCollation(Utility.java:2252)
	at com.mysql.clusterj.tie.Utility.getCharsetConverter(Utility.java:2239)
	at com.mysql.clusterj.tie.Utility.encode(Utility.java:2197)
	at com.mysql.clusterj.tie.NdbRecordImpl.setString(NdbRecordImpl.java:472)
	at com.mysql.clusterj.tie.NdbRecordOperationImpl.equalString(NdbRecordOperationImpl.java:398)
	at com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl$20.operationEqual(AbstractDomainFieldHandlerImpl.java:1940)
	at com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl.operationEqual(AbstractDomainFieldHandlerImpl.java:320)
	at com.mysql.clusterj.core.query.PropertyImpl.operationEqual(PropertyImpl.java:71)
	at com.mysql.clusterj.core.query.EqualPredicateImpl.operationEqual(EqualPredicateImpl.java:86)
	at com.mysql.clusterj.core.query.CandidateIndexImpl$CandidateColumnImpl.operationSetKeys(CandidateIndexImpl.java:511)
	at com.mysql.clusterj.core.query.CandidateIndexImpl$CandidateColumnImpl.access$700(CandidateIndexImpl.java:356)
	at com.mysql.clusterj.core.query.CandidateIndexImpl.operationSetKeys(CandidateIndexImpl.java:347)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultData(QueryDomainTypeImpl.java:240)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultList(QueryDomainTypeImpl.java:181)
	at com.mysql.clusterj.core.query.QueryImpl.getResultList(QueryImpl.java:146)
	at com.tile.services.DAO.TestDAO.lambda$f$0(TestDAO.java:31)
	at com.tile.services.db.NDBQuerySession.withClusterJSession(NDBQuerySession.java:85)
	at com.tile.services.DAO.TestDAO.f(TestDAO.java:23)
	at com.tile.services.DAO.TestDAO.main(TestDAO.java:37)
Exception in thread "main" com.mysql.clusterj.ClusterJDatastoreException: For field identifier column identifier valueDelegate key String, error executing operationEqual. Caused by java.lang.NullPointerException:null
	at com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl.operationEqual(AbstractDomainFieldHandlerImpl.java:323)
	at com.mysql.clusterj.core.query.PropertyImpl.operationEqual(PropertyImpl.java:71)
	at com.mysql.clusterj.core.query.EqualPredicateImpl.operationEqual(EqualPredicateImpl.java:86)
	at com.mysql.clusterj.core.query.CandidateIndexImpl$CandidateColumnImpl.operationSetKeys(CandidateIndexImpl.java:511)
	at com.mysql.clusterj.core.query.CandidateIndexImpl$CandidateColumnImpl.access$700(CandidateIndexImpl.java:356)
	at com.mysql.clusterj.core.query.CandidateIndexImpl.operationSetKeys(CandidateIndexImpl.java:347)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultData(QueryDomainTypeImpl.java:240)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultList(QueryDomainTypeImpl.java:181)
	at com.mysql.clusterj.core.query.QueryImpl.getResultList(QueryImpl.java:146)
	at com.tile.services.DAO.TestDAO.lambda$f$0(TestDAO.java:31)
	at com.tile.services.db.NDBQuerySession.withClusterJSession(NDBQuerySession.java:85)
	at com.tile.services.DAO.TestDAO.f(TestDAO.java:23)
	at com.tile.services.DAO.TestDAO.main(TestDAO.java:37)
Caused by: java.lang.NullPointerException
	at com.mysql.clusterj.tie.Utility.addCollation(Utility.java:2252)
	at com.mysql.clusterj.tie.Utility.getCharsetConverter(Utility.java:2239)
	at com.mysql.clusterj.tie.Utility.encode(Utility.java:2197)
	at com.mysql.clusterj.tie.NdbRecordImpl.setString(NdbRecordImpl.java:472)
	at com.mysql.clusterj.tie.NdbRecordOperationImpl.equalString(NdbRecordOperationImpl.java:398)
	at com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl$20.operationEqual(AbstractDomainFieldHandlerImpl.java:1940)
	at com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl.operationEqual(AbstractDomainFieldHandlerImpl.java:320)
	... 12 more
java.lang.NullPointerException
	at com.mysql.clusterj.tie.Utility.addCollation(Utility.java:2252)
	at com.mysql.clusterj.tie.Utility.getCharsetConverter(Utility.java:2239)
	at com.mysql.clusterj.tie.Utility.encode(Utility.java:2197)
	at com.mysql.clusterj.tie.NdbRecordImpl.setString(NdbRecordImpl.java:472)
	at com.mysql.clusterj.tie.NdbRecordOperationImpl.equalString(NdbRecordOperationImpl.java:398)
	at com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl$20.operationEqual(AbstractDomainFieldHandlerImpl.java:1940)
	at com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl.operationEqual(AbstractDomainFieldHandlerImpl.java:320)
	at com.mysql.clusterj.core.query.PropertyImpl.operationEqual(PropertyImpl.java:71)
	at com.mysql.clusterj.core.query.EqualPredicateImpl.operationEqual(EqualPredicateImpl.java:86)
	at com.mysql.clusterj.core.query.CandidateIndexImpl$CandidateColumnImpl.operationSetKeys(CandidateIndexImpl.java:511)
	at com.mysql.clusterj.core.query.CandidateIndexImpl$CandidateColumnImpl.access$700(CandidateIndexImpl.java:356)
	at com.mysql.clusterj.core.query.CandidateIndexImpl.operationSetKeys(CandidateIndexImpl.java:347)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultData(QueryDomainTypeImpl.java:240)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultList(QueryDomainTypeImpl.java:181)
	at com.mysql.clusterj.core.query.QueryImpl.getResultList(QueryImpl.java:146)
	at com.tile.services.DAO.TestDAO.lambda$f$0(TestDAO.java:31)
	at com.tile.services.db.NDBQuerySession.withClusterJSession(NDBQuerySession.java:85)
	at com.tile.services.DAO.TestDAO.f(TestDAO.java:23)
	at com.tile.services.DAO.TestDAO.main(TestDAO.java:37)

Suggested fix:
Unknown; I have not been able to find ClusterJ's source code. It may have the same underlying problem as https://bugs.mysql.com/bug.php?id=81874
[7 Dec 2017 16:13] MySQL Verification Team
Hi,

I can verify this. Can't see a workaround, sorry. Hopefully this can be fixed.

all best
Bogdan
[19 Feb 2019 10:50] Lakshmi Narayanan Sreethar
Posted by developer:
 
This is not a bug.
There is an issue in the model interface.

In the table definition, the type of the `identifier` column in BIGINT. But in the model interface Test, the getter and setter for that columns use a String type. In ClusterJ, all the MySQL Data types are mapped to certain Java Data types. The behaviour is undefined if the model classes don't follow these mappings. More information can be found at https://dev.mysql.com/doc/ndbapi/en/mccj-using-clusterj-mappings.html

In this particular issue, the getter setters has to be changed to long(or Long) type.
i.e.

@PrimaryKey
@Column(name = "identifier")
long getIdentifier();
void setIdentifier(long identifier);

This will fix this issue.