JDK-6515710 : CachedRowSetImpl.acceptChanges might throw NPE in JDK1.6 (was working fine 1.5)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.sql
  • Affected Version: 6
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-01-22
  • Updated: 2011-02-16
  • Resolved: 2007-07-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6u4 b01Fixed
Description
FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
If you:
-> have a CachedRowSet on table with an auto-increment primary key in a mySQL database.
-> you are inserting a new row
-> you are calling acceptChanges
you will get an NPE.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1/ in your mySQL database creates a database "ilog_demos"
2/ in your mySQL "test" database creates a table "activities"
3/ modify the attached .java  to use your login/passwd to mysql and change "server" by your mySQL server.
4/ run the sample
you'll get a NPE because the code is calling toString() on the value of the primary key. However the primary key column is in auto increment mode, and thus until the row has been commited to the database its value is NULL. => NULL.toString() = NPE.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
no NPE, the row is added.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.NullPointerException
	at com.sun.rowset.internal.CachedRowSetWriter.insertNewRow(CachedRowSetWriter.java:766)
	at com.sun.rowset.internal.CachedRowSetWriter.writeData(CachedRowSetWriter.java:313)
	at com.sun.rowset.CachedRowSetImpl.acceptChanges(CachedRowSetImpl.java:862)
	at ilog.views.util.data.TestCachedRowSet.main(TestCachedRowSet.java:65)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
///// SOURCE CODE /////
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;

import javax.sql.rowset.CachedRowSet;

import com.sun.rowset.CachedRowSetImpl;

public class TestCachedRowSet {
  final static String databaseURL = "jdbc:mysql://server/ilog_demos";
  final static String user = "xxxx";
  final static String passwd = "yyy";
  final static String driverName = "com.mysql.jdbc.Driver";
  final static String TABLE_NAME = "activities";
  final static Timestamp newDateValue = new Timestamp(1000*(System.currentTimeMillis()/1000));
  final static String newStringValue = "newStringValue";

   // CJO 01/07
  public static void main(String[] arg) throws SQLException, IOException, ClassNotFoundException {
    // driver
    Class.forName(driverName);
    
    // first fresh up the database
    Connection con = DriverManager.getConnection(databaseURL, user, passwd);
    InputStream stream = TestCachedRowSet.class.getResourceAsStream("script.sql");
    BufferedReader breader = new BufferedReader(new InputStreamReader(stream));
    Statement statement = con.createStatement();
    while (breader.ready()) {
      statement.executeUpdate(breader.readLine());
    }
    stream.close();
    con.close();
    
    // prepare CachedRowSet
    CachedRowSet rowSet = new CachedRowSetImpl();
    rowSet.setPageSize(0);
    con = DriverManager.getConnection(databaseURL, user, passwd);
    rowSet.setCommand("select * from activities");
    rowSet.setReadOnly(false);
    rowSet.execute(con);
    
    // the actual test
    addRow(rowSet,
        new Object[] {null, newStringValue, newDateValue, newDateValue, new Integer(200), null});
    rowSet.acceptChanges();
  }
  
  private static void addRow(CachedRowSet rowSet, Object[] rowData) throws SQLException
  {
    rowSet.moveToInsertRow();
    // this can happen we don't have any row data at all for the moment
    if (rowData != null) {
      for (int i = 0; i < rowData.length; i++) {
        rowSet.updateObject(i+1, rowData[i]);
      }
    }
    rowSet.insertRow();
    rowSet.moveToCurrentRow();
  }
}

// script.sql file to fill the table
DROP TABLE IF EXISTS activities;
CREATE TABLE activities (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), startTime TIMESTAMP NULL, endTime TIMESTAMP NULL, parentID INT, originalID VARCHAR(20)) ENGINE=InnoDB;
INSERT INTO activities VALUES(NULL, 'Project Summary', STR_TO_DATE('6-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '18-5-2001 0:00:00', '%e-%c-%Y %H:%i:%S'), NULL, 'A-Root');
INSERT INTO activities SELECT NULL, 'Gather Requirements', STR_TO_DATE('6-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '21-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-1' FROM activities as parent WHERE parent.originalID='A-Root';
INSERT INTO activities SELECT NULL, 'Talk to customers', STR_TO_DATE('6-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '9-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-1.1' FROM activities as parent WHERE parent.originalID='A-1';
INSERT INTO activities SELECT NULL, 'Compile customer list', STR_TO_DATE('6-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '7-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-1.1.1' FROM activities as parent WHERE parent.originalID='A-1.1';
INSERT INTO activities SELECT NULL, 'Contact customers', STR_TO_DATE('7-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '9-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-1.1.2' FROM activities as parent WHERE parent.originalID='A-1.1';
INSERT INTO activities SELECT NULL, 'Write up requirements', STR_TO_DATE('7-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '21-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-1.2' FROM activities as parent WHERE parent.originalID='A-1';
INSERT INTO activities SELECT NULL, 'Marketing Specification', STR_TO_DATE('20-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '25-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-2' FROM activities as parent WHERE parent.originalID='A-Root';
INSERT INTO activities SELECT NULL, 'First Draft Specification', STR_TO_DATE('20-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '23-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-2.1' FROM activities as parent WHERE parent.originalID='A-2';
INSERT INTO activities SELECT NULL, 'Second Draft Specification', STR_TO_DATE('20-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '25-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-2.2' FROM activities as parent WHERE parent.originalID='A-2';
INSERT INTO activities SELECT NULL, 'Proof of Concept', STR_TO_DATE('27-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '1-12-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3' FROM activities as parent WHERE parent.originalID='A-Root';
INSERT INTO activities SELECT NULL, 'Rough Design', STR_TO_DATE('27-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '30-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.1' FROM activities as parent WHERE parent.originalID='A-3';
INSERT INTO activities SELECT NULL, 'CAD Layout', STR_TO_DATE('27-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '28-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.1.1' FROM activities as parent WHERE parent.originalID='A-3.1';
INSERT INTO activities SELECT NULL, 'Detailing', STR_TO_DATE('27-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '30-10-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.1.2' FROM activities as parent WHERE parent.originalID='A-3.1';
INSERT INTO activities SELECT NULL, 'Fabricate Prototype', STR_TO_DATE('3-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '10-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.2' FROM activities as parent WHERE parent.originalID='A-3';
INSERT INTO activities SELECT NULL, 'Order Materials', STR_TO_DATE('3-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '4-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.2.1' FROM activities as parent WHERE parent.originalID='A-3.2';
INSERT INTO activities SELECT NULL, 'Machining', STR_TO_DATE('3-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '10-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.2.2' FROM activities as parent WHERE parent.originalID='A-3.2';
INSERT INTO activities SELECT NULL, 'Burn-in Testing', STR_TO_DATE('17-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '24-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.3' FROM activities as parent WHERE parent.originalID='A-3';
INSERT INTO activities SELECT NULL, 'Prepare Demo', STR_TO_DATE('24-11-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '1-12-2000 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-3.4' FROM activities as parent WHERE parent.originalID='A-3';
INSERT INTO activities SELECT NULL, 'Design and Development', STR_TO_DATE('1-12-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '18-5-2001 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-4' FROM activities as parent WHERE parent.originalID='A-Root';
INSERT INTO activities SELECT NULL, 'Phase I Development', STR_TO_DATE('1-12-2000 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '19-1-2001 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-4.1' FROM activities as parent WHERE parent.originalID='A-4';
INSERT INTO activities SELECT NULL, 'Phase II Development', STR_TO_DATE('19-1-2001 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '23-2-2001 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-4.2' FROM activities as parent WHERE parent.originalID='A-4';
INSERT INTO activities SELECT NULL, 'Phase III Development', STR_TO_DATE('23-2-2001 0:00:00', '%e-%c-%Y %H:%i:%S'),STR_TO_DATE( '18-5-2001 0:00:00', '%e-%c-%Y %H:%i:%S'), parent.id, 'A-4.3' FROM activities as parent WHERE parent.originalID='A-4';

---------- END SOURCE ----------

Comments
EVALUATION Code needs to be modified keeping in mind that auto increment keys of mysql may be null
11-07-2007