Bug #87178 Query containing AND against table containing TEXT column results in an NPE
Submitted: 24 Jul 2017 18:25 Modified: 25 Aug 2018 15:42
Reporter: Michael Seydel Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Cluster: Cluster/J Severity:S2 (Serious)
Version:7.5.5 OS:MacOS
Assigned to: CPU Architecture:Any
Tags: and, ClusterJ, getlength, npe, NullPointerException, text

[24 Jul 2017 18:25] Michael Seydel
Description:
Performing a query containing an AND on a table containing a TEXT column results in an NullPointerException. Here is the stacktrace:

Exception in thread "main" com.mysql.clusterj.ClusterJException: Exception executing query. Caused by java.lang.NullPointerException:null
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultList(QueryDomainTypeImpl.java:194)
	at com.mysql.clusterj.core.query.QueryImpl.getResultList(QueryImpl.java:144)
	at com.tile.bugrepro.BugRepro.repro(UserAppDataDAO.java:111)
	at com.tile.bugrepro.BugRepro.main(UserAppDataDAO.java:73)
Caused by: java.lang.NullPointerException
	at com.mysql.clusterj.tie.BlobImpl.getLength(BlobImpl.java:85)
	at com.mysql.clusterj.tie.NdbRecordBlobImpl.readData(NdbRecordBlobImpl.java:97)
	at com.mysql.clusterj.tie.NdbRecordOperationImpl.loadBlobValues(NdbRecordOperationImpl.java:950)
	at com.mysql.clusterj.tie.NdbRecordScanResultDataImpl.next(NdbRecordScanResultDataImpl.java:138)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultList(QueryDomainTypeImpl.java:183)
	... 7 more
java.lang.NullPointerException
	at com.mysql.clusterj.tie.BlobImpl.getLength(BlobImpl.java:85)
	at com.mysql.clusterj.tie.NdbRecordBlobImpl.readData(NdbRecordBlobImpl.java:97)
	at com.mysql.clusterj.tie.NdbRecordOperationImpl.loadBlobValues(NdbRecordOperationImpl.java:950)
	at com.mysql.clusterj.tie.NdbRecordScanResultDataImpl.next(NdbRecordScanResultDataImpl.java:138)
	at com.mysql.clusterj.core.query.QueryDomainTypeImpl.getResultList(QueryDomainTypeImpl.java:183)
	at com.mysql.clusterj.core.query.QueryImpl.getResultList(QueryImpl.java:144)
	at com.tile.services.DAO.UserAppDataDAO.repro(UserAppDataDAO.java:111)
	at com.tile.services.DAO.UserAppDataDAO.lambda$main$2(UserAppDataDAO.java:77)
	at com.tile.services.db.BareboneDatabaseAPIs.runInTransaction(BareboneDatabaseAPIs.java:260)
	at com.tile.services.db.BareboneDatabaseAPIs.runInTransaction(BareboneDatabaseAPIs.java:241)
	at com.tile.services.db.NDBDataSource.withTransaction(NDBDataSource.java:54)
	at com.tile.services.DAO.UserAppDataDAO.main(UserAppDataDAO.java:76)

This seems related to another filed bug: https://bugs.mysql.com/bug.php?id=78682

How to repeat:
Create the following table and insert a record:

CREATE TABLE bug_repro (
    id VARCHAR(36) CHARACTER SET latin1 NOT NULL,
    data TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
    revision INT DEFAULT 0 NOT NULL,

    PRIMARY KEY(id) USING HASH
) engine=ndb
;

INSERT INTO bug_repro VALUES ('1234', '{}', 1);

Run the following code:

private static void repro(final Session clusterJSession) {
    final QueryDomainType<BugRepro> snapshotDomain = clusterJSession.getQueryBuilder()
            .createQueryDefinition(BugRepro.class);

    final Query<BugRepro> snapshotQuery = clusterJSession.createQuery(snapshotDomain);
    snapshotQuery.setParameter("id", "1234");
    snapshotQuery.setParameter("revision", 0);

    snapshotDomain.where(snapshotDomain.get("id").equal(snapshotDomain.param("id"))
            // the following line is required to reproduce the problem; removing it results in expected behavior
            .and(snapshotDomain.get("revision").greaterThan(snapshotDomain.param("revision")))
    );

    snapshotQuery.getResultList(); // throws an NPE
}

@PersistenceCapable(table = "bug_repro")
public interface BugRepro {
    @PrimaryKey
    @Column(name = "id", allowsNull = "NO")
    String getId();

    void setId(String id);

    @Column(name = "data", allowsNull = "YES")
    String getData();

    void setData(String data);

    @Column(name = "revision", allowsNull = "NO")
    int getRevision();

    void setRevision(int revision);
}

Expected: the record that we inserted.
Actual: NPE.
[25 Jul 2017 8:33] MySQL Verification Team
[root@localhost mysql]# javac -classpath /usr/local/mysql/share/java/clusterj-7.5.6.jar:/usr/local/connector/mysql-connector-java-5.1.43/mysql-connector-java-5.1.43-bin.jar:. bug87178.java
[root@localhost mysql]# java -Djava.library.path=/usr/local/mysql/lib/ -classpath /usr/local/mysql/share/java/clusterj-7.5.6.jar:/usr/local/connector/mysql-connector-java-5.1.43/mysql-connector-java-5.1.43-bin.jar:. bug87178
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.core.metadata.DomainTypeHandlerFactoryImpl <clinit>
INFO: Found 0 DomainTypeHandlerFactories
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for Decimal Pool bufferSize 68
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 5
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 8
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 15
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 31
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 47
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 48
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 49
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 94
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for DBImplErrorBufferPool bufferSize 300
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for CoordinatedTransactionIdBufferPool bufferSize 44
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for PartitionKeyBufferPool bufferSize 10000
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.ClusterConnectionImpl <init>
INFO: Created cluster connection 'localhost:1186' with node id 0, mgm timeout 30,000.
Jul 25, 2017 10:32:50 AM com.mysql.clusterj.tie.VariableByteBufferPoolImpl <init>
INFO: ByteBuffer pools initialized: [256, 10240, 102400, 1048576].
Jul 25, 2017 10:32:51 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for bug_repro bufferSize 60
DANGE: Exception executing query. Caused by java.lang.NullPointerException:null
DANGE: [Ljava.lang.StackTraceElement;@68fb2c38
[root@localhost mysql]# cat bug87178.java
import com.mysql.jdbc.*;
import com.mysql.clusterj.*;
import com.mysql.clusterj.query.*;
import com.mysql.clusterj.annotation.*;
import java.util.*;

public class bug87178{

        @PersistenceCapable(table = "bug_repro")
        public interface BugRepro {
            @PrimaryKey
            @Column(name = "id", allowsNull = "NO")
            String getId();

            void setId(String id);

            @Column(name = "data", allowsNull = "YES")
            String getData();

            void setData(String data);

            @Column(name = "revision", allowsNull = "NO")
            int getRevision();

            void setRevision(int revision);
        }

   public static void main(String[] args) {
      try{
          Properties props = new Properties();
          props.put("com.mysql.clusterj.connectstring", "localhost:1186");
          props.put("com.mysql.clusterj.database", "test");

          SessionFactory factory = ClusterJHelper.getSessionFactory(props);
          Session clusterJSession = factory.getSession();

          final QueryDomainType<BugRepro> snapshotDomain = clusterJSession.getQueryBuilder().createQueryDefinition(BugRepro.class);
          final Query<BugRepro> snapshotQuery = clusterJSession.createQuery(snapshotDomain);

          snapshotQuery.setParameter("id", "1234");
          snapshotQuery.setParameter("revision", 0);

          snapshotDomain.where(snapshotDomain.get("id").equal(snapshotDomain.param("id"))
            // the following line is required to reproduce the problem; removing it results in expected behavior
            .and(snapshotDomain.get("revision").greaterThan(snapshotDomain.param("revision")))
          );

          snapshotQuery.getResultList(); // throws an NPE
      } catch (Exception ex){
          System.out.println("DANGE: " + ex.getMessage());
          System.out.println("DANGE: " + ex.getStackTrace());
          return;
      }

    }
}

[root@localhost mysql]#
[25 Jul 2017 8:34] MySQL Verification Team
[root@localhost mysql]# javac -classpath /usr/local/mysql/share/java/clusterj-7.5.6.jar:/usr/local/connector/mysql-connector-java-5.1.43/mysql-connector-java-5.1.43-bin.jar:. bug87178.java                                  [root@localhost mysql]# java -Djava.library.path=/usr/local/mysql/lib/ -classpath /usr/local/mysql/share/java/clusterj-7.5.6.jar:/usr/local/connector/mysql-connector-java-5.1.43/mysql-connector-java-5.1.43-bin.jar:. bug87178
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.core.metadata.DomainTypeHandlerFactoryImpl <clinit>
INFO: Found 0 DomainTypeHandlerFactories
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for Decimal Pool bufferSize 68
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 5
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 8
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 15
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 31
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 47
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 48
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 49
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.Utility addCollation
INFO: Adding charset converter latin1 for collation 94
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for DBImplErrorBufferPool bufferSize 300
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for CoordinatedTransactionIdBufferPool bufferSize 44
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for PartitionKeyBufferPool bufferSize 10000
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.ClusterConnectionImpl <init>
INFO: Created cluster connection 'localhost:1186' with node id 0, mgm timeout 30,000.
Jul 25, 2017 10:34:12 AM com.mysql.clusterj.tie.VariableByteBufferPoolImpl <init>
INFO: ByteBuffer pools initialized: [256, 10240, 102400, 1048576].
Jul 25, 2017 10:34:13 AM com.mysql.clusterj.tie.FixedByteBufferPoolImpl <init>
INFO: FixedByteBufferPoolImpl<init> for bug_repro bufferSize 60
[root@localhost mysql]# cat bug87178.java
import com.mysql.jdbc.*;
import com.mysql.clusterj.*;
import com.mysql.clusterj.query.*;
import com.mysql.clusterj.annotation.*;
import java.util.*;

public class bug87178{

        @PersistenceCapable(table = "bug_repro")
        public interface BugRepro {
            @PrimaryKey
            @Column(name = "id", allowsNull = "NO")
            String getId();

            void setId(String id);

            @Column(name = "data", allowsNull = "YES")
            String getData();

            void setData(String data);

            @Column(name = "revision", allowsNull = "NO")
            int getRevision();

            void setRevision(int revision);
        }

   public static void main(String[] args) {
      try{
          Properties props = new Properties();
          props.put("com.mysql.clusterj.connectstring", "localhost:1186");
          props.put("com.mysql.clusterj.database", "test");

          SessionFactory factory = ClusterJHelper.getSessionFactory(props);
          Session clusterJSession = factory.getSession();

          final QueryDomainType<BugRepro> snapshotDomain = clusterJSession.getQueryBuilder().createQueryDefinition(BugRepro.class);
          final Query<BugRepro> snapshotQuery = clusterJSession.createQuery(snapshotDomain);

          snapshotQuery.setParameter("id", "1234");
          snapshotQuery.setParameter("revision", 0);

          snapshotDomain.where(snapshotDomain.get("id").equal(snapshotDomain.param("id"))
            // the following line is required to reproduce the problem; removing it results in expected behavior
            //.and(snapshotDomain.get("revision").greaterThan(snapshotDomain.param("revision")))
          );

          snapshotQuery.getResultList(); // throws an NPE
      } catch (Exception ex){
          System.out.println("DANGE: " + ex.getMessage());
          System.out.println("DANGE: " + ex.getStackTrace());
          return;
      }

    }
}

[root@localhost mysql]#
[25 Jul 2017 8:35] MySQL Verification Team
Thanks for submission, verified as described.

all best
Bogdan
[25 Aug 2018 15:42] Lakshmi Narayanan Sreethar
Duplicate of Bug#91242