Bug #38554 Stored procedures unreliable/unusable with combination with result set streaming
Submitted: 5 Aug 2008 8:51 Modified: 14 Aug 2008 18:31
Reporter: P Eger
Status: Analyzing
Category:Connector/J Severity:S2 (Serious)
Version:5.0.8 OS:Any
Assigned to: Target Version:

[5 Aug 2008 8:51] P Eger
Description:
For certain types of stored procedures, cannot enable result set streaming via
setFetchSize(Integer.MIN_VALUE), doing so results in the following exception reliably
when the sproc attempts to execute. You can see from test code that multiple result sets
are definitely not used.

Tried with Connector/J 5.1.6 & 5.0.8, mysql 5.0.66a enterprise.

java.sql.SQLException: Can not use streaming results with multiple result statements
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:910)
	at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:1470)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1787)
	at com.mysql.jdbc.Connection.execSQL(Connection.java:3283)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1332)
	at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1467)
	at com.mysql.jdbc.CallableStatement.executeQuery(CallableStatement.java:794)
	at TestSprocMRS.test(TestSprocMRS.java:27)

How to repeat:
Create table/procedure as follows:
----------------------------------------------

mysql> create table t1(c0 int);
Query OK, 0 rows affected (0.02 sec)

mysql> create procedure test1(p0 int) select * from t1 where c0=p0;
Query OK, 0 rows affected (0.00 sec)

Then execute following code:
----------------------------------------------
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import org.junit.Test;

public class TestSprocMRS {
	
	@Test
	public void testSproc() throws Exception
	{
    	com.mysql.jdbc.jdbc2.optional.MysqlDataSource nds = new
com.mysql.jdbc.jdbc2.optional.MysqlDataSource();
    		
    	nds.setUser("user");
    	nds.setPassword("password");
    	nds.setServerName("localhost");
    	nds.setPortNumber(3306);
    	nds.setDatabaseName("testdb");
    	
        Connection conn = nds.getConnection();
		try {
			PreparedStatement ps = conn.prepareCall("{call
test1(?)}",ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
	    	ps.setFetchSize(Integer.MIN_VALUE);
	    	
	    	ps.setInt(1, 1);

	    	ResultSet rs = ps.executeQuery(); //<-- EXCEPTION THROWN HERE??
	    	
	    	while(rs.next()) ;
	    
	    	rs.close();
	    	ps.close();
	    	
			
		} finally {
			conn.close();
		}
	}
}

Suggested fix:
1) Disable result set streaming, or 
2) Don't use stored procedures.

Either of course are not desirable (or possible) in our case.
[5 Aug 2008 8:56] P Eger
Note that the problem only seems to occur with an empty result set, inserting a row lets
the unit test pass.

mysql> insert into t1(c0) values (1);
Query OK, 1 row affected (0.00 sec)

>> run test code (SUCCESS)

mysql> truncate table t1;
Query OK, 1 row affected (0.00 sec)

>> run test code (FAILURE w/exception)
[6 Aug 2008 21:45] P Eger
happens on both linux and windows x64, changing to OS: Any.
[7 Aug 2008 19:05] P Eger
Occurs on 5.1.26-rc also
[13 Aug 2008 17:04] Tonci Grgin
Hi Eger and thanks for your report.

What happens if you use CallableStatements? Can you retest with:
CallableStatement callable = this.conn.prepareCall("{call test1(?)}");?
[13 Aug 2008 17:25] Tonci Grgin
Test case, using SVN repository sources and our test fw

Attachment: TestBug38554.java (text/x-java), 2.24 KiB.

[13 Aug 2008 17:26] Tonci Grgin
I do not see bug here, please review my test case and output/log:

080813 17:19:20	      2 Connect     root@localhost on test
		      2 Query       /* @MYSQL_CJ_FULL_PROD_NAME@ ( Revision: @MYSQL_CJ_REVISION@ )
*/SHOW VARIABLES WHERE Variable_name ='language' OR Variable_name = 'net_write_timeout'
OR Variable_name = 'interactive_timeout' OR Variable_name = 'wait_timeout' OR
Variable_name = 'character_set_client' OR Variable_name = 'character_set_connection' OR
Variable_name = 'character_set' OR Variable_name = 'character_set_server' OR
Variable_name = 'tx_isolation' OR Variable_name = 'transaction_isolation' OR
Variable_name = 'character_set_results' OR Variable_name = 'timezone' OR Variable_name =
'time_zone' OR Variable_name = 'system_time_zone' OR Variable_name =
'lower_case_table_names' OR Variable_name = 'max_allowed_packet' OR Variable_name =
'net_buffer_length' OR Variable_name = 'sql_mode' OR Variable_name = 'query_cache_type'
OR Variable_name = 'query_cache_size' OR Variable_name = 'init_connect'
		      2 Query       SHOW COLLATION
		      2 Query       SET character_set_results = NULL
		      2 Query       SET autocommit=1
		      2 Query       SET sql_mode='STRICT_TRANS_TABLES'
		      2 Query       SELECT VERSION()
		      2 Query       DROP TABLE IF EXISTS test38554
		      2 Query       CREATE TABLE test38554 ( c0 INT NOT NULL PRIMARY KEY )
ENGINE=InnoDB DEFAULT CHARSET=latin1
		      2 Query       DROP PROCEDURE IF EXISTS test_function38554
080813 17:19:21	      2 Query       CREATE PROCEDURE test_function38554 (p0 INT)BEGIN
SELECT * FROM test38554 WHERE c0 = p0;END
		      2 Query       USE `test`
		      2 Query       SELECT DATABASE()
		      2 Query       USE `test`
		      2 Query       SHOW CREATE PROCEDURE `test`.`test_function38554`
		      2 Query       CALL test_function38554(2)
		      2 Quit       

			  
			  
.Loading JDBC driver 'com.mysql.jdbc.Driver'
Done.

Done.

Connected to 5.0.68-pb10-log
java.vm.version         : 1.5.0_12-b04
java.vm.vendor          : Sun Microsystems Inc.
java.runtime.version    : 1.5.0_12-b04
os.name                 : Windows XP
os.version              : null
sun.management.compiler : HotSpot Client Compiler

Time: 0,469

OK (1 test)
[13 Aug 2008 18:52] P Eger
Apologies, it appears Connector/J 5.1.6 is *not* affected. Connector/J 5.0.8 is the
effected version, with which I am able to reproduce the error reliably.

Also, tried using CallableStatement in test code, bug still occurs.
[13 Aug 2008 19:00] Tonci Grgin
Hi again. I am unable to reproduce the problem with attached test case on latest c/J 5.0
sources too...
.Loading JDBC driver 'com.mysql.jdbc.Driver'
Done.

Done.

java.vm.version         : 1.5.0_12-b04
java.vm.vendor          : Sun Microsystems Inc.Connected to 5.0.68-pb10-log

java.runtime.version    : 1.5.0_12-b04
os.name                 : Windows XP
os.version              : null
sun.management.compiler : HotSpot Client Compiler

Time: 1,297

OK (1 test)

I suggest to either build your own c/J driver from sources or take latest snapshot and
retest.
[13 Aug 2008 20:51] P Eger
mysql-connector-java-5.0-nightly-20080801-bin.jar shows the same problem as 5.0.8, this is
the most recent snapshot listed on http://downloads.mysql.com/snapshots.php#connector-j. I
would be happy to test HEAD, but I could not find instructions anywhere on how to access
your VCS repository?
[14 Aug 2008 9:28] Todd Farmer
Will attach updated test case.  Able to repeat with fetch size = Integer.MIN_VALUE,
related to the following code in MysqlIO.readAllResults():

        boolean serverHasMoreResults = (this.serverStatus &
            SERVER_MORE_RESULTS_EXISTS) != 0;

Comparing the 5.1 and 5.0 sources, it appears that handling of multiple result sets with
streaming has been added (it is labeled with TODO in 5.0 sources).

5.0 version:

        //
        // TODO: We need to support streaming of multiple result sets
        //
        if (serverHasMoreResults && streamResults) {
            clearInputStream();

            throw SQLError.createSQLException(Messages.getString("MysqlIO.23"),
//$NON-NLS-1$
                SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
        }

5.1 version:

        if (serverHasMoreResults && streamResults) {
            //clearInputStream();
//
            //throw SQLError.createSQLException(Messages.getString("MysqlIO.23"),
//$NON-NLS-1$
                //SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
        	if (topLevelResultSet.getUpdateCount() != -1) {
        		tackOnMoreStreamingResults(topLevelResultSet);
        	}
        	
        	reclaimLargeReusablePacket();
        	
        	return topLevelResultSet;
        }

I'm unsure whether this should be ported back to 5.0 or simply documented as a
limitation.  I'll assess the complexity of porting back the 5.1 code, but we should also
solicit Mark's feedback.
[14 Aug 2008 9:29] Todd Farmer
Revised test case

Attachment: TestBug38554.java (text/x-java), 2.35 KiB.

[14 Aug 2008 18:31] P Eger
Glad you could reproduce. I'm not sure what it looks like at a driver/protocol level, but
it definitely seems wrong that a sproc that only does a simple "select ..." could fail
because of this multiple result set limitation. As it stands, RS streaming looks to be
unusable with sprocs on 5.0.X. We're able to update to 5.1.X so this is okay for us
(though possibly not others).