Derby
  1. Derby
  2. DERBY-979

NullPointerException in store when using holdable resultset to get next tuple on a deleted table

    Details

    • Urgency:
      Normal
    • Issue & fix info:
      Repro attached

      Description

      Derby uses table intent locks to prevent a table from being dropped while there is an open cursor on it.
      However, for holdable cursors, the lock is released after the commit. This allows a drop table command to drop the table. The next call to ResultSet.next then get a NullPointerException from the store module.

      A potential fix, could be to handle this situation in store, and to give a meaningful error message.

      Transaction history:
      T1: select * from table1
      T1: cursor.next()
      T1: commit

      T2: drop table table1
      T2: commit

      T3: cursor.next()..

      Result: T3 get NullPointerException.

      To reproduce: Add the following testcase to ConcurrencyTest.java (see DERBY-934) (hopefully someone commits those tests soon)

      /**

      • Test that as long as an cursor is open on a table, no
      • other transaction can delete the table.
        */
        public void testTableIntentLockWithHoldableCursor()
        throws SQLException
        {
        con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        con.setAutoCommit(true);
        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
        ResultSet.CONCUR_UPDATABLE);
        ResultSet rs = s.executeQuery("select * from t1");
        rs.next();
        updateTuple(rs);
        con.commit();

      Connection con2 = getNewConnection();
      con2.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

      try

      { PreparedStatement ps2 = con2.prepareStatement ("drop table t1"); ps2.executeUpdate(); con2.commit(); // .. WHAT happens ? rs.next(); updateTuple(rs); }

      catch (SQLException e)

      { System.out.println(e.getMessage() + ":" + e.getSQLState()); printStackTrace(e); assertEquals("Unexpected SQL state", LOCK_TIMEOUT_SQL_STATE, e.getSQLState()); }

      finally

      { con2.close(); }


      }

      java.lang.NullPointerException
      at org.apache.derby.impl.store.access.conglomerate.OpenConglomerate.latchPageAndRepositionScan(OpenConglomerate.java:264)
      at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(GenericScanController.java:613)
      at org.apache.derby.impl.store.access.heap.HeapScan.fetchNext(HeapScan.java:207)
      at org.apache.derby.impl.sql.execute.TableScanResultSet.getNextRowCore(TableScanResultSet.java:681)
      at org.apache.derby.impl.sql.execute.BasicNoPutResultSetImpl.getNextRow(BasicNoPutResultSetImpl.java:474)
      at org.apache.derby.impl.jdbc.EmbedResultSet.movePosition(EmbedResultSet.java:371)
      at org.apache.derby.impl.jdbc.EmbedResultSet.next(EmbedResultSet.java:320)
      at org.apache.derbyTesting.functionTests.tests.jdbcapi.ConcurrencyTest.testTableIntentLockWithHoldableCursor(ConcurrencyTest.java:877)
      ..

      The NullPointerException is wrapped in a SQLException, which just makes the bug more confusing for the user.

      1. testCase.diff
        3 kB
        Rick Hillegas

        Activity

        Hide
        Rick Hillegas added a comment -

        Triaged for 10.5.3: assigned normal urgency and noted that a repro is attached.

        Show
        Rick Hillegas added a comment - Triaged for 10.5.3: assigned normal urgency and noted that a repro is attached.
        Hide
        Rick Hillegas added a comment -

        Attaching testCase.diff. This patch rewarms the test case supplied in the comment above. With this patch, ConcurrencyTest still raises an NPE, although the NPE has moved. The new NPE is:

        Caused by: java.lang.NullPointerException
        at org.apache.derby.impl.store.access.conglomerate.GenericScanController.reopenAfterEndTransaction(GenericScanController.java:1041)
        at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(GenericScanController.java:604)
        at org.apache.derby.impl.store.access.heap.HeapScan.fetchNext(HeapScan.java:238)
        at org.apache.derby.impl.sql.execute.TableScanResultSet.getNextRowCore(TableScanResultSet.java:577)
        at org.apache.derby.impl.sql.execute.BasicNoPutResultSetImpl.getNextRow(BasicNoPutResultSetImpl.java:477)
        at org.apache.derby.impl.jdbc.EmbedResultSet.movePosition(EmbedResultSet.java:429)

        Show
        Rick Hillegas added a comment - Attaching testCase.diff. This patch rewarms the test case supplied in the comment above. With this patch, ConcurrencyTest still raises an NPE, although the NPE has moved. The new NPE is: Caused by: java.lang.NullPointerException at org.apache.derby.impl.store.access.conglomerate.GenericScanController.reopenAfterEndTransaction(GenericScanController.java:1041) at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(GenericScanController.java:604) at org.apache.derby.impl.store.access.heap.HeapScan.fetchNext(HeapScan.java:238) at org.apache.derby.impl.sql.execute.TableScanResultSet.getNextRowCore(TableScanResultSet.java:577) at org.apache.derby.impl.sql.execute.BasicNoPutResultSetImpl.getNextRow(BasicNoPutResultSetImpl.java:477) at org.apache.derby.impl.jdbc.EmbedResultSet.movePosition(EmbedResultSet.java:429)
        Hide
        Mike Matrigali added a comment -

        Triaged for 10.9, no changes.

        Show
        Mike Matrigali added a comment - Triaged for 10.9, no changes.
        Hide
        Knut Anders Hatlen added a comment -

        One doesn't need to drop the table to see this problem. The same NullPointerException is thrown if the table has been compressed with SYSCS_COMPRESS_TABLE. Script that shows how to reproduce:

        ij version 10.10
        ij> connect 'jdbc:derby:db;create=true' as c1;
        ij> create table t(x int);
        0 rows inserted/updated/deleted
        ij> insert into t values 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17;
        17 rows inserted/updated/deleted
        ij> connect 'jdbc:derby:db' as c2;
        ij(C2)> autocommit off;
        ij(C2)> get cursor c as 'select * from t';
        ij(C2)> next c;
        X
        -----------
        1
        ij(C2)> commit;
        ij(C2)> set connection c1;
        ij(C1)> call syscs_util.syscs_compress_table('APP', 'T', 0);
        0 rows inserted/updated/deleted
        ij(C1)> set connection c2;
        ij(C2)> next c;
        X
        -----------
        2
        ij(C2)> next c;
        X
        -----------
        3
        ij(C2)> next c;
        X
        -----------
        4
        ij(C2)> next c;
        X
        -----------
        5
        ij(C2)> next c;
        X
        -----------
        6
        ij(C2)> next c;
        X
        -----------
        7
        ij(C2)> next c;
        X
        -----------
        8
        ij(C2)> next c;
        X
        -----------
        9
        ij(C2)> next c;
        X
        -----------
        10
        ij(C2)> next c;
        X
        -----------
        11
        ij(C2)> next c;
        X
        -----------
        12
        ij(C2)> next c;
        X
        -----------
        13
        ij(C2)> next c;
        X
        -----------
        14
        ij(C2)> next c;
        X
        -----------
        15
        ij(C2)> next c;
        X
        -----------
        16
        ij(C2)> next c;
        ERROR XJ001: Java exception: ': java.lang.NullPointerException'.
        (...)
        Caused by: java.lang.NullPointerException
        at org.apache.derby.impl.store.access.conglomerate.GenericScanController.reopenAfterEndTransaction(GenericScanController.java:1040)
        at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(GenericScanController.java:603)
        at org.apache.derby.impl.store.access.heap.HeapScan.fetchNextGroup(HeapScan.java:322)
        at org.apache.derby.impl.sql.execute.BulkTableScanResultSet.reloadArray(BulkTableScanResultSet.java:353)
        at org.apache.derby.impl.sql.execute.BulkTableScanResultSet.getNextRowCore(BulkTableScanResultSet.java:308)
        at org.apache.derby.impl.sql.execute.BasicNoPutResultSetImpl.getNextRow(BasicNoPutResultSetImpl.java:478)
        at org.apache.derby.impl.jdbc.EmbedResultSet.movePosition(EmbedResultSet.java:432)
        ... 10 more

        Show
        Knut Anders Hatlen added a comment - One doesn't need to drop the table to see this problem. The same NullPointerException is thrown if the table has been compressed with SYSCS_COMPRESS_TABLE. Script that shows how to reproduce: ij version 10.10 ij> connect 'jdbc:derby:db;create=true' as c1; ij> create table t(x int); 0 rows inserted/updated/deleted ij> insert into t values 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17; 17 rows inserted/updated/deleted ij> connect 'jdbc:derby:db' as c2; ij(C2)> autocommit off; ij(C2)> get cursor c as 'select * from t'; ij(C2)> next c; X ----------- 1 ij(C2)> commit; ij(C2)> set connection c1; ij(C1)> call syscs_util.syscs_compress_table('APP', 'T', 0); 0 rows inserted/updated/deleted ij(C1)> set connection c2; ij(C2)> next c; X ----------- 2 ij(C2)> next c; X ----------- 3 ij(C2)> next c; X ----------- 4 ij(C2)> next c; X ----------- 5 ij(C2)> next c; X ----------- 6 ij(C2)> next c; X ----------- 7 ij(C2)> next c; X ----------- 8 ij(C2)> next c; X ----------- 9 ij(C2)> next c; X ----------- 10 ij(C2)> next c; X ----------- 11 ij(C2)> next c; X ----------- 12 ij(C2)> next c; X ----------- 13 ij(C2)> next c; X ----------- 14 ij(C2)> next c; X ----------- 15 ij(C2)> next c; X ----------- 16 ij(C2)> next c; ERROR XJ001: Java exception: ': java.lang.NullPointerException'. (...) Caused by: java.lang.NullPointerException at org.apache.derby.impl.store.access.conglomerate.GenericScanController.reopenAfterEndTransaction(GenericScanController.java:1040) at org.apache.derby.impl.store.access.conglomerate.GenericScanController.fetchRows(GenericScanController.java:603) at org.apache.derby.impl.store.access.heap.HeapScan.fetchNextGroup(HeapScan.java:322) at org.apache.derby.impl.sql.execute.BulkTableScanResultSet.reloadArray(BulkTableScanResultSet.java:353) at org.apache.derby.impl.sql.execute.BulkTableScanResultSet.getNextRowCore(BulkTableScanResultSet.java:308) at org.apache.derby.impl.sql.execute.BasicNoPutResultSetImpl.getNextRow(BasicNoPutResultSetImpl.java:478) at org.apache.derby.impl.jdbc.EmbedResultSet.movePosition(EmbedResultSet.java:432) ... 10 more

          People

          • Assignee:
            Unassigned
            Reporter:
            Andreas Korneliussen
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development