Bug #81755 Interpret BIT fails from MysqlaUtils class
Submitted: 7 Jun 2016 15:41 Modified: 21 Jun 2016 17:35
Reporter: Illia Lavryk Email Updates:
Status: Verified Impact on me:
None 
Category:Connector / J Severity:S3 (Non-critical)
Version:6.0.2 OS:Any
Assigned to: CPU Architecture:Any
Tags: Interpret, MysqlaUtils

[7 Jun 2016 15:41] Illia Lavryk
Description:
I created a table with a BIT column. In my java app i tried to get it from ResultSet and it always fail. I noticed through debug mode that it fails in next method:
public static long bitToLong(byte[] bytes, int offset, int length)

from MysqlaUtils class.

The input data was
bytes - as 1024 length  {1,57,1,0,10,49,57,56,56,45...}
offset - 3
length - 1

StackTrace is:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at com.mysql.cj.mysqla.MysqlaUtils.bitToLong(MysqlaUtils.java:68)
	at com.mysql.cj.core.io.MysqlTextValueDecoder.decodeBit(MysqlTextValueDecoder.java:231)
	at com.mysql.cj.jdbc.ResultSetRow.decodeAndCreateReturnValue(ResultSetRow.java:170)
	at com.mysql.cj.jdbc.ResultSetRow.getValueFromBytes(ResultSetRow.java:269)
	at com.mysql.cj.jdbc.BufferRow.getValue(BufferRow.java:349)
	at com.mysql.cj.jdbc.ResultSetImpl.getNonStringValueFromRow(ResultSetImpl.java:813)
	at com.mysql.cj.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:904)
	at com.mysql.cj.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:908)

How to repeat:
it is not so hard to reproduce, Just call with parameters a specified before in description 
So in this method we declare

long[] steps = new long[length];

and 'length' in my case was 1

and the problem with store result look at this

for (int i = offset + length - 1; i >= offset; i--) {
    steps[i] = (long) (bytes[i] & 0xff) << shift;
    shift += 8;
}

'i' kept offset + length value which was in my case as 3

Suggested fix:
steps[i - offset] = (long) (bytes[i] & 0xff) << shift;
[9 Jun 2016 9:56] Chiranjeevi Battula
Hello   Illia Lavryk,

Thank you for the bug report.
Could you please provide repeatable test case (exact steps/sample code, create table script  etc. - please make it as private if you prefer) to confirm this issue at our end?

Thanks,
Chiranjeevi.
[15 Jun 2016 11:29] Chiranjeevi Battula
Hello  Илья Лаврик,

Thank you for your feedback.
Could you please provide complete repeatable test case (exact steps, sample project/code without using external components, create table scripts, full stack trace  etc. - please make it as private if you prefer) to confirm this issue at our end?

Thanks,
Chiranjeevi.
[31 Jul 2016 1:20] Patrick Herrera
Hi, have the exact same issue. 
I'm using Spring/JPA/Hibernate, but my stack trace is fundamentally the same:

at com.mysql.cj.mysqla.MysqlaUtils.bitToLong(MysqlaUtils.java:68)
	at com.mysql.cj.core.io.MysqlTextValueDecoder.decodeBit(MysqlTextValueDecoder.java:231)
	at com.mysql.cj.jdbc.ResultSetRow.decodeAndCreateReturnValue(ResultSetRow.java:170)
	at com.mysql.cj.jdbc.ResultSetRow.getValueFromBytes(ResultSetRow.java:269)
	at com.mysql.cj.jdbc.BufferRow.getValue(BufferRow.java:349)
	at com.mysql.cj.jdbc.ResultSetImpl.getNonStringValueFromRow(ResultSetImpl.java:813)
	at com.mysql.cj.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:904)
	at com.mysql.cj.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:908)
	at org.hibernate.type.descriptor.sql.BooleanTypeDescriptor$2.doExtract(BooleanTypeDescriptor.java:59)
	at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47)
... snip
	at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:501)
	at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:371)
	at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:216)
	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1326)
	at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
	at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:606)
	at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:483)
	at org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:50)
	at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:114)
	at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:78)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:102)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:92)

I've tried changing the underlying column to a tiny int or a full int with no difference except the array index being checked (and out of bounds) changes.

The query that is being executed in this case is effectively: select * from Competition as c where c.active = true

I'm connecting to Mysql 5.6.27 and can confirm this issue occurs in version 6.0.3 and 6.0.2 of the mysql-connector.

However, going back to version 5.1.39 and the problem disappears.
[5 Dec 2017 10:28] Rudi Vankeirsbilck
I ran into the same issue with version 5.1.23 but it does not always occur, it depends on the bit value that I am reading. I think you will be able to reproduce this with the following code constructs:

CREATE TABLE `EXAMPLE` (
  `ID` varchar(80) NOT NULL,
  `BITS` bit(7) DEFAULT NULL,
  PRIMARY KEY (`ID`),
);
INSERT INTO EXAMPLE VALUES('FINE', 0b1111111);
INSERT INTO EXAMPLE VALUES('FINE-TOO', 0b1100000);
INSERT INTO EXAMPLE VALUES('CRASH', 0b0011111);

Connection connection = ...;
PreparedStatement statement = connection.prepareStatement("select BITS from EXAMPLE where ID = 'CRASH'");
ResultSet rs = statement.executeQuery();
rs.getInt(1);

Note that running the same code for IDs "FINE" and "FINE-TOO" does not produce the error.