Bug #87704 The stream gets the result set ,the driver side get wrong about getLong().
Submitted: 8 Sep 2017 8:52 Modified: 15 Sep 2017 22:32
Reporter: zongfang zhang Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S1 (Critical)
Version:connector J 5.1.44 ,MySQL server 5.7.16 OS:SUSE (suse11sp3)
Assigned to: CPU Architecture:Any
Tags: connector J ,useCursorFetch=true

[8 Sep 2017 8:52] zongfang zhang
Description:
0. Connector/J - 5.1.44, MySQL Enterprise Server - 5.7.16
1. Stored procedure with out parameter(BIGINT type).
2. URL = "jdbc:mysql://10.137.49.160:3306/admin?useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSize=500&prepStmtCacheSqlLimit=2048&useOldAliasMetadataBehavior=true&rewriteBatchedStatements=true&useCursorFetch=true&defaultFetchSize=100";
3. Code to execute stored procedure:
4. If (1) and (2) are omitted then it works as expected, in they present exception will be thrown.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 23
	at com.mysql.jdbc.SingleByteCharsetConverter.toString(SingleByteCharsetConverter.java:303)
	at com.mysql.jdbc.ResultSetRow.getString(ResultSetRow.java:699)
	at com.mysql.jdbc.BufferRow.getString(BufferRow.java:527)
	at com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2682)
	at com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2650)
	at com.mysql.jdbc.CallableStatement.getLong(CallableStatement.java:1347)
	at com.test.mysql.Main.main(Main.java:52)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
5.If I don't use "useCursorFetch=true&defaultFetchSize=100",it run normally.Output as follows:
C:\jdk1.6.0_45_x64\bin\java -Didea.launcher.port=7532 -Didea.launcher.bin.path=D:\Tools\JetBrains\ideaIU-2016.3.4\bin -classpath C:\Users\w00192156\AppData\Local\Temp\classpath.jar -Dfile.encoding=UTF-8 com.intellij.rt.execution.application.AppMain com.test.mysql.Main
Thu Sep 07 17:00:34 GMT+08:00 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
30314567
STR30314567

How to repeat:
step1. Create stored procedure with integer or bigint out parameter
DROP PROCEDURE  PROC_TEST;
CREATE PROCEDURE PROC_TEST(
  IN PARAMIN BIGINT,
  OUT PARAM_OUT_LONG BIGINT,
  OUT PARAM_OUT_STR VARCHAR(100)
)
BEGIN
  SET PARAM_OUT_LONG = PARAMIN + 100000;
  SET PARAM_OUT_STR = concat('STR' ,PARAM_OUT_LONG);
END;
step2:Create connection to DB with useCursorFetch=true&defaultFetchSize=100
for example:
private static final String urladmin = "jdbc:mysql://10.137.49.160:3306/admin?useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSize=500&prepStmtCacheSqlLimit=2048&useOldAliasMetadataBehavior=true&rewriteBatchedStatements=true&useCursorFetch=true&defaultFetchSize=100";
step3: Create java.sql.CallableStatement for this stored procedure 
public static void main(String args[]) throws SQLException, XAException
{

   // Connection con = DriverManager.getConnection(url, "admin", "Abc1234%");
    Connection con = DriverManager.getConnection(urladmin, "admin", "Abc1234%");
    CallableStatement callableStatement = null;
    try
    {
        callableStatement = con.prepareCall("call PROC_TEST(?,?,?)");
        callableStatement.setLong(1, 30214567L);
        callableStatement.registerOutParameter(2, Types.BIGINT);
        callableStatement.registerOutParameter(3, Types.VARCHAR);
        callableStatement.execute();
        System.out.println(callableStatement.getLong(2));
        System.out.println(callableStatement.getString(3));
    }finally
    {
        if(callableStatement != null)
        {
            callableStatement.close();
        }
        if(con != null)
        {
            con.close();
        }
    }

4. Register type of out parameter.
5. Execute it.
6. Exception will be thrown.
[8 Sep 2017 9:28] Chiranjeevi Battula
Hello zongfang,

Thank you for the bug report and test case.
Verified this behavior on MySQL Connector / J 5.1.44.

Thanks,
Chiranjeevi.
[15 Sep 2017 22:32] Daniel So
Posted by developer:
 
Added the following entry to the Connector/J 5.1.45 changelog:

"When server-side prepared statements and cursor-based result sets were used, exceptions were thrown when applications made calls to get output parameters of INTEGER or BIGINT type from a result set."