Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8327113

Unexpected Exception after CachedRowSet.acceptChanges()

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      ADDITIONAL SYSTEM INFORMATION :
      H2 database used to reproduce the problem. Maven dependency provided with the program.

      A DESCRIPTION OF THE PROBLEM :
      rs.acceptChanges gets an exception.

      The top level problem is the generated SQL
          "SELECT SWINGSET_BASE_TEST_PK, SS_TEXT_FIELD FROM
          FROM SUPPLIERS_AND_PARTS.PUBLIC.swingset_base_test_data; WHERE
          SWINGSET_BASE_TEST_PK = ? AND SS_TEXT_FIELD = ? "

      NOTE the ";" between the table name and the "WHERE".

      This statement is built by `CachedRowSetWriter.updateOriginalRow()`
          pstmt = con.prepareStatement(selectCmd + updateWhere,
                      ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
      around line 493.

      The bug could be in `CachedeRowSetImpl.buildTableName()`, it returns a name
      with an appended ";".

      But I wonder about `CachedeRowSetImpl.getTableName`. If `setTableName()` has not
      been called, then shouldn't the metadata be used if available.
      Maybe the result of parsing the SELECT statement should be the last resort.
      Note that the javadoc for `CachedeRowSetImpl.getTableName` references
      "See Also: ResultSetMetaData.getTableName(int)"

      Also, in `CachedRowSetWriter.initSQLStatements` plays a part.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile/run the provided program.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No exception. database updated successfully. Test program outputs "### xxx" at completion.

      Note that this problem does not occur if a JdbcRowSet is used (try it in the example by setting
      "use_crs" to false.
      ACTUAL -
      Exceptions.

      ---------- BEGIN SOURCE ----------
      /*****************************************
          <dependency>
              <groupId>com.h2database</groupId>
              <artifactId>h2</artifactId>
              <version>2.2.224</version>
          </dependency>
      *****************************************/

      package play.syncerror;

      import java.io.StringReader;
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.SQLException;

      import javax.sql.RowSet;
      import javax.sql.rowset.CachedRowSet;
      import javax.sql.rowset.RowSetProvider;

      import org.h2.tools.RunScript;

      public class SyncError
      {
          static String initialDB =
            """
            CREATE SEQUENCE IF NOT EXISTS swingset_base_test_seq START WITH 1000;
            CREATE TABLE IF NOT EXISTS swingset_base_test_data
            (
                swingset_base_test_pk INTEGER DEFAULT nextval('swingset_base_test_seq') NOT NULL PRIMARY KEY,
                ss_text_field VARCHAR(100)
            );
            MERGE INTO swingset_base_test_data VALUES (1,'This is TextField 1') ;
            MERGE INTO swingset_base_test_data VALUES (2,'This is TextField 2') ;
            """;

          public static void main(String[] args)
                  throws ClassNotFoundException, SQLException
          {
              String url = "jdbc:h2:mem:suppliers_and_parts;TRACE_LEVEL_SYSTEM_OUT=3";
              //String url = "jdbc:h2:mem:suppliers_and_parts";

              boolean use_crs = true;

              Class.forName("org.h2.Driver");

              Connection conn = DriverManager.getConnection(url);
              RunScript.execute(conn, new StringReader(initialDB));

              System.err.printf("### use_crs: %s\n", use_crs);

              RowSet rs;
              if (use_crs) {
                  rs = RowSetProvider.newFactory().createCachedRowSet();
              } else {
                  rs = RowSetProvider.newFactory().createJdbcRowSet(); // NO PROBLEM
              }
              rs.setUrl(url);

              //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | <<<<<<<<<<<<<
              rs.setCommand("SELECT * FROM swingset_base_test_data;"); // NOTE THE TRAILING ';'

              rs.execute();
              rs.first();
              Object o = rs.getObject(2);
              System.err.printf("### %s\n", o);
              rs.updateString(2, "xxx");
              rs.updateRow();

              if (use_crs)
                  ((CachedRowSet)rs).acceptChanges(); // <<<<<<<<<<<<<<<< EXCEPTION

              rs.execute();
              rs.first();
              o = rs.getObject(2);
              System.err.printf("### %s\n", o);
          }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      Two workarounds
      - Remove the trailing semicolon from the select statement.
      - Use sr.setTableName().

      FREQUENCY : always


      Attachments

        Activity

          People

            lancea Lance Andersen
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated: