Bug #31823 JDBC setNull throws ArrayIndexOutOfBoundsException
Submitted: 24 Oct 2007 19:29 Modified: 3 Dec 2007 7:20
Reporter: Larry Brunelle Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:5.0.8 OS:Any
Assigned to: CPU Architecture:Any
Tags: JDBC setNull ArrayIndexOutOfBoundsException

[24 Oct 2007 19:29] Larry Brunelle
Description:
Problem occurs when a stored FUNCTION (not PROCEDURE) is addressed as a
CallableStatement and setNull() is called to set a field null.  It seems
apparent when the LAST field in the row is set null, at least.

Inspection of code in PreparedStatement.java suggests that the member
array isNull[] is not constructed long enough (this may not be the sole
problem).  The behavior seems not to obtain in PROCEDURES, but FUNCTIONS;
is there an issue with dealing with the return value?

How to repeat:
The following Java code (please insert correct local connection values)
illustrates the problem with output thus:

[machine prompt]$ java TestMySQL
database=MySQL version 5.0.46-enterprise-gpl-log
driver=MySQL-AB JDBC Driver version mysql-connector-java-5.0.8 ( Revision: ${svn.Revision} )
id=1
This next call to setNull() will throw ArrayIndexOutOfBoundsException. Why?
java.lang.ArrayIndexOutOfBoundsException: 2
        at com.mysql.jdbc.PreparedStatement.setNull(PreparedStatement.java:2864)
        at TestMySQL.runTest(TestMySQL.java:52)
        at TestMySQL.main(TestMySQL.java:10)

============================================================================

import java.io.*;
import java.sql.*;

public class TestMySQL
{
    public static void main(String[] args)
    {
        try
            {
                runTest();
            }
        catch(Exception exception)
            {
                exception.printStackTrace();
                System.exit(1);
            }
    }

    private static void runTest() throws Exception
    {
        // Connect to the database
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://<hostname>:<mysql port>/<db/schema name>","<db login>","<db password>");

        // Print connection meta-data
        DatabaseMetaData meta = connection.getMetaData();
        System.out.println("database=" + meta.getDatabaseProductName() + " version " + meta.getDatabaseProductVersion());
        System.out.println("driver=" + meta.getDriverName() + " version " + meta.getDriverVersion());

        // Create test table and function
        Statement statement = connection.createStatement();
        statement.executeUpdate("DROP TABLE IF EXISTS test_table");
        statement.executeUpdate("CREATE TABLE test_table (value_1 BIGINT PRIMARY KEY,value_2 VARCHAR(20)) ENGINE=InnoDB");
        statement.executeUpdate("DROP FUNCTION IF EXISTS add_test_table");
        statement.executeUpdate("CREATE FUNCTION add_test_table(value_1_v BIGINT,value_2_v VARCHAR(20)) RETURNS BIGINT " +
                                "DETERMINISTIC MODIFIES SQL DATA BEGIN INSERT INTO test_table VALUES (value_1_v,value_2_v); " +
                                "RETURN value_1_v; END;");

        // Prepare the function call
        CallableStatement callable = connection.prepareCall("{? = call add_test_table(?,?)}");
        callable.registerOutParameter(1,Types.BIGINT);

        // Add row with non-null value
        callable.setLong(2,1);
        callable.setString(3,"Non-null value");
        callable.executeUpdate();
        System.out.println("id=" + callable.getLong(1));

        // Add row with null value
        callable.setLong(2,2);
        System.out.println("This next call to setNull() will throw ArrayIndexOutOfBoundsException. Why?");
        callable.setNull(3,Types.VARCHAR);
        System.out.println("Well, maybe everything's OK.");
        callable.executeUpdate();
        System.out.println("id=" + callable.getLong(1));
        callable.close();

        // Cleanup test objects
        statement.executeUpdate("DROP TABLE test_table");
        statement.executeUpdate("DROP FUNCTION add_test_table");

        // Free resources
        statement.close();
        connection.close();
    }
}
[24 Oct 2007 19:47] Larry Brunelle
Test code was provided my Marc Gfeller.
[24 Oct 2007 21:13] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/36302
[25 Oct 2007 22:43] Larry Brunelle
Patch tested here today and looks like good output.
We are using the patched connector and await the
containing release.
Thank you!!
[6 Nov 2007 19:00] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/37212
[19 Nov 2007 0:57] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/38019
[19 Nov 2007 2:52] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/38024
[3 Dec 2007 7:20] MC Brown
A note has been added to the 5.1.6 changelog: 

Using CallableStatement.setNull() on a stored function would throw an ArrayIndexOutOfBounds exception when setting the last parameter to null.