1

I'm using CachedRowSet. But when I call the insertRow() method, there is a SQLException failed to insert row.

Here is my code:

static final String DATABASE_URL = "jdbc:mysql://localhost:3306/javapos";
static final String USERNAME = "root";
static final String PASSWORD = "sbc";

public static void main (String [] agr) throws SQLException
{
    CachedRowSetImpl rs = new CachedRowSetImpl();
    rs.setUrl(DATABASE_URL);
    rs.setUsername(USERNAME);
    rs.setPassword(PASSWORD);

    rs.setCommand("select * from uom order by itemid");
    rs.execute();

    while(rs.next()){
        System.out.println(rs.getString("itemid") + "  -  " + rs.getString("uom"));
    }

    rs.moveToInsertRow();
    rs.updateString(2,"Sample code");
    rs.insertRow();
    rs.moveToCurrentRow();

    rs.acceptChanges();
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
ram
  • 29
  • 10

2 Answers2

3

When you call insertRow(), the Reference Implementation of CachedRowSet performs a check if all required columns have been populated and otherwise it throws an exception (source from Grepcode CachedRowSet.insertRow(), line numbers don't exactly match):

if (onInsertRow == false ||
        insertRow.isCompleteRow(RowSetMD) == false) {
    throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.failedins").toString());
}

The check is performed in InsertRow.isCompleteRow(RowSetMetaData):

public boolean isCompleteRow(RowSetMetaData RowSetMD) throws SQLException {
    for (int i = 0; i < cols; i++) {
        if (colsInserted.get(i) == false &&
                RowSetMD.isNullable(i + 1) == ResultSetMetaData.columnNoNulls) {
            return false;
        }
    }
    return true;
}

In other words, when inserting a row you must provide a value for all columns that are not nullable (this includes the primary key). There seem to be two ways to work around this:

  • Setting a (random) value. This does require that your primary key is always generated (even if a value is provided).
  • Explicitly setting the column to null using updateNull. Using setNull doesn't work: it provides the same error, and using setObject(idx, null) results in a NullPointerException

When using your code with these changes I get an SQLException when calling acceptChanges as the implementation doesn't disable autoCommit (it seems to have been commented out), but it does explicitly call commit (which is invalid when in autoCommit). This doesn't seem to be easy to solve, except maybe explicitly providing a connection on execute, or creating your own implementation.

I think these kind of issues actually demonstrate how little the RowSet implementations are actually used (otherwise they would already have been flushed out long ago).

Note however that if this were the actual code you needed and don't need the disconnected characteristics of the CachedRowSet, then you could simply use an updatable result set.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • The solution is to provide a connection in non-auto commit mode to `acceptConnection()`, or to so configure its connection or its DataSource if that's what you're using. I agree about the lack of use, I've found several other oddities and bugs. Nobody seems to use this at all. Pity really, there are some good ideas in there. I'm going to open a documentation bug report on it. – user207421 Sep 11 '15 at 22:14
  • updateNull() works with auto incrementing primary key – Don Apr 01 '22 at 20:26
  • @Don That is the second point I list under _"There seem to be two ways to work around this"_. – Mark Rotteveel Apr 02 '22 at 06:26
0

Example:

        beginAddRow(crs);
        crs.updateString("TABLE_TYPE", "TABLE");
        
        continueAddRow();
        crs.updateString("TABLE_TYPE", "INDEX");
        endAddRow();
    static public CachedRowSet beginAddRow(CachedRowSet crs) throws SQLException {
        crs.moveToInsertRow(); // onInsertRow = true
        return crs;
    }

    static public CachedRowSet continueAddRow(CachedRowSet crs) throws SQLException {
        crs.insertRow();
        crs.moveToCurrentRow();
        crs.moveToInsertRow();
        return crs;
    }

    static public CachedRowSet endAddRow(CachedRowSet crs) throws SQLException {
        crs.insertRow();
        crs.moveToCurrentRow(); // onInsertRow = false;
        crs.beforeFirst();
        return crs;
    }
Leo Tu
  • 1
  • 1
  • Hi! Usually answers based only on code are deleted. It would be good if you can comment your code and explain why it solves the problem. Can be obvious for you, but maybe not for other readers – King Midas Aug 29 '22 at 09:25