Derby
  1. Derby
  2. DERBY-4488

Nullpointer when performing INSERT INTO

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 10.3.1.4, 10.3.2.1, 10.3.3.0, 10.4.1.3, 10.4.2.0, 10.5.1.1, 10.5.2.0, 10.5.3.0, 10.6.1.0
    • Fix Version/s: 10.3.3.1, 10.4.2.1, 10.5.3.1, 10.6.1.0
    • Component/s: SQL
    • Labels:
      None
    • Urgency:
      Normal
    • Issue & fix info:
      Repro attached
    • Bug behavior facts:
      Regression

      Description

      To replicate, execute the following 4 queries:

      CREATE TABLE feed (fst INTEGER, snd VARCHAR(50), UNIQUE(fst))

      INSERT INTO feed VALUES (1, 'fst')

      CREATE TABLE tbl (col1 INTEGER, col2 INTEGER NOT NULL REFERENCES feed (fst) ON DELETE RESTRICT ON UPDATE RESTRICT)

      INSERT INTO tbl(col1) SELECT 1 FROM feed

      The result of the last INSERT INTO query is:
      java.lang.NullPointerException
      at org.apache.derby.impl.store.access.btree.BTreeScan.initScanParams(Unknown Source)
      at org.apache.derby.impl.store.access.btree.BTreeScan.reopenScan(Unknown Source)
      at org.apache.derby.impl.sql.execute.TableScanResultSet.reopenScanController(Unknown Source)
      at org.apache.derby.impl.sql.execute.TableScanResultSet.reopenScanController(Unknown Source)
      at org.apache.derby.impl.sql.execute.TableScanResultSet.reopenCore(Unknown Source)
      at org.apache.derby.impl.sql.execute.BulkTableScanResultSet.reopenCore(Unknown Source)
      at org.apache.derby.impl.sql.execute.ProjectRestrictResultSet.reopenCore(Unknown Source)
      at org.apache.derby.impl.sql.execute.NormalizeResultSet.reopenCore(Unknown Source)
      at org.apache.derby.impl.sql.execute.InsertResultSet.open(Unknown Source)
      at org.apache.derby.impl.sql.GenericPreparedStatement.executeStmt(Unknown Source)
      at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
      at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
      at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown Source)
      at org.apache.derby.impl.jdbc.EmbedPreparedStatement.execute(Unknown Source)

      1. debug info.txt
        5 kB
        Huib
      2. d4488.sql
        0.3 kB
        Knut Anders Hatlen
      3. setTopResult.diff
        10 kB
        Knut Anders Hatlen

        Activity

        Hide
        Huib added a comment -

        Attached is the derby log file with:
        derby.language.logQueryPlan=true
        derby.stream.error.logSeverityLevel=20000

        Show
        Huib added a comment - Attached is the derby log file with: derby.language.logQueryPlan=true derby.stream.error.logSeverityLevel=20000
        Hide
        Knut Anders Hatlen added a comment -

        I tried to reproduce this on 10.5.3.0, starting with a clean database. Here's what I see:

        ij> CREATE TABLE feed (fst INTEGER, snd VARCHAR(50), UNIQUE(fst));
        0 rows inserted/updated/deleted
        ij> INSERT INTO feed VALUES (1, 'fst');
        1 row inserted/updated/deleted
        ij> CREATE TABLE tbl (col1 INTEGER, col2 INTEGER NOT NULL REFERENCES feed (fst) ON DELETE RESTRICT ON UPDATE RESTRICT);
        0 rows inserted/updated/deleted
        ij> INSERT INTO tbl(col1) SELECT 1 FROM feed;
        ERROR 23502: Column 'COL2' cannot accept a NULL value.

        Did I miss something?

        Show
        Knut Anders Hatlen added a comment - I tried to reproduce this on 10.5.3.0, starting with a clean database. Here's what I see: ij> CREATE TABLE feed (fst INTEGER, snd VARCHAR(50), UNIQUE(fst)); 0 rows inserted/updated/deleted ij> INSERT INTO feed VALUES (1, 'fst'); 1 row inserted/updated/deleted ij> CREATE TABLE tbl (col1 INTEGER, col2 INTEGER NOT NULL REFERENCES feed (fst) ON DELETE RESTRICT ON UPDATE RESTRICT); 0 rows inserted/updated/deleted ij> INSERT INTO tbl(col1) SELECT 1 FROM feed; ERROR 23502: Column 'COL2' cannot accept a NULL value. Did I miss something?
        Hide
        Knut Anders Hatlen added a comment -

        Looking at the log file, it seems like you saw the same (expected) error message twice. But on the third execution it resulted in a NullPointerException. I also see this now:

        ij> CREATE TABLE feed (fst INTEGER, snd VARCHAR(50), UNIQUE(fst));
        0 rows inserted/updated/deleted
        ij> INSERT INTO feed VALUES (1, 'fst');
        1 row inserted/updated/deleted
        ij> CREATE TABLE tbl (col1 INTEGER, col2 INTEGER NOT NULL REFERENCES feed (fst) ON DELETE RESTRICT ON UPDATE RESTRICT);
        0 rows inserted/updated/deleted
        ij> prepare ps as 'INSERT INTO tbl(col1) SELECT 1 FROM feed';
        ij> execute ps;
        ERROR 23502: Column 'COL2' cannot accept a NULL value.
        ij> execute ps;
        ERROR 23502: Column 'COL2' cannot accept a NULL value.
        ij> execute ps;
        ERROR XJ001: Java exception: ': java.lang.NullPointerException'.

        Show
        Knut Anders Hatlen added a comment - Looking at the log file, it seems like you saw the same (expected) error message twice. But on the third execution it resulted in a NullPointerException. I also see this now: ij> CREATE TABLE feed (fst INTEGER, snd VARCHAR(50), UNIQUE(fst)); 0 rows inserted/updated/deleted ij> INSERT INTO feed VALUES (1, 'fst'); 1 row inserted/updated/deleted ij> CREATE TABLE tbl (col1 INTEGER, col2 INTEGER NOT NULL REFERENCES feed (fst) ON DELETE RESTRICT ON UPDATE RESTRICT); 0 rows inserted/updated/deleted ij> prepare ps as 'INSERT INTO tbl(col1) SELECT 1 FROM feed'; ij> execute ps; ERROR 23502: Column 'COL2' cannot accept a NULL value. ij> execute ps; ERROR 23502: Column 'COL2' cannot accept a NULL value. ij> execute ps; ERROR XJ001: Java exception: ': java.lang.NullPointerException'.
        Hide
        Knut Anders Hatlen added a comment -

        This is a regression in Derby 10.3.1.4. I suspect DERBY-827 because it happens on re-execution of a prepared statement.

        Show
        Knut Anders Hatlen added a comment - This is a regression in Derby 10.3.1.4. I suspect DERBY-827 because it happens on re-execution of a prepared statement.
        Hide
        Knut Anders Hatlen added a comment -

        Uploading repro script.

        Show
        Knut Anders Hatlen added a comment - Uploading repro script.
        Hide
        Dag H. Wanvik added a comment -

        More data points.
        It is a bit weird it only happens on the third execution, not the second. I checked a bit and found that
        Knut is right, the third time, the result set is reopened which does not seem to work. But it seems the first time, when the error happens, the InsertResultSet gets its "cleanup" method called (from ContextManager.cleanupOnError), so the second time we execute, InsertResultSet looks clean, and it calls sourceResultSet.openCore. However, on the execution and ensuing error, the cleanup method is not called (context manager gone?!), so on the third execution, InsertResultSet does no longer look unused, and so sourceResultSet.reopenCore is called, which then fails.

        Show
        Dag H. Wanvik added a comment - More data points. It is a bit weird it only happens on the third execution, not the second. I checked a bit and found that Knut is right, the third time, the result set is reopened which does not seem to work. But it seems the first time, when the error happens, the InsertResultSet gets its "cleanup" method called (from ContextManager.cleanupOnError), so the second time we execute, InsertResultSet looks clean, and it calls sourceResultSet.openCore. However, on the execution and ensuing error, the cleanup method is not called (context manager gone?!), so on the third execution, InsertResultSet does no longer look unused, and so sourceResultSet.reopenCore is called, which then fails.
        Hide
        Knut Anders Hatlen added a comment -

        On the second execution, GenericStatementContext.topResultSet is null, and that's why the cleanup is not performed the second time.

        The topResultSet field of the statement context is set in NoRowsResultSetImpl's constructor, so on the first execution it is non-null. When cleaning up after the error, it is set to null to prepare the statement context for reuse. Then, on re-execution, InsertResultSet sets it in normalInsertCore(). However, normalInsertCore() is not called until after getNextRowCore() has been called, so topResultSet is still null when the exception is thrown on the second execution.

        DeleteResultSet and UpdateResultSet set topResultSet earlier in their setup() methods. I think InsertResultSet should do the same. It might also make sense to push this code into NoRowsResultSetImpl.setup(), and perhaps remove it from NoRowsResultSetImpl's constructor too.

        Show
        Knut Anders Hatlen added a comment - On the second execution, GenericStatementContext.topResultSet is null, and that's why the cleanup is not performed the second time. The topResultSet field of the statement context is set in NoRowsResultSetImpl's constructor, so on the first execution it is non-null. When cleaning up after the error, it is set to null to prepare the statement context for reuse. Then, on re-execution, InsertResultSet sets it in normalInsertCore(). However, normalInsertCore() is not called until after getNextRowCore() has been called, so topResultSet is still null when the exception is thrown on the second execution. DeleteResultSet and UpdateResultSet set topResultSet earlier in their setup() methods. I think InsertResultSet should do the same. It might also make sense to push this code into NoRowsResultSetImpl.setup(), and perhaps remove it from NoRowsResultSetImpl's constructor too.
        Hide
        Knut Anders Hatlen added a comment -

        Here's a patch which adds a test case and moves the setting of the statement context's topResultSet to NoRowsResultSetImpl.setup(). This allows some simplifications in the sub-classes, like removing code that sets topResultSet and also some throws clauses.

        lang.ResultSetsFromPreparedStatementTest ran cleanly with this patch. Will start the other regression tests now.

        Show
        Knut Anders Hatlen added a comment - Here's a patch which adds a test case and moves the setting of the statement context's topResultSet to NoRowsResultSetImpl.setup(). This allows some simplifications in the sub-classes, like removing code that sets topResultSet and also some throws clauses. lang.ResultSetsFromPreparedStatementTest ran cleanly with this patch. Will start the other regression tests now.
        Hide
        Knut Anders Hatlen added a comment -

        All the regression tests passed with the patch.

        Show
        Knut Anders Hatlen added a comment - All the regression tests passed with the patch.
        Hide
        Bryan Pendleton added a comment -

        +1 to simplifying code and moving it to the superclass. Thanks for taking a look at this issue.

        Show
        Bryan Pendleton added a comment - +1 to simplifying code and moving it to the superclass. Thanks for taking a look at this issue.
        Hide
        Knut Anders Hatlen added a comment -

        Thanks, Bryan! I've committed the patch to trunk with revision 903108.

        I also plan to back-port the fix to 10.5 before marking the issue as resolved. Since this bug was a regression in 10.3.1.4, the fix may be a candidate for back-porting all the way back to 10.3.

        I'm reclassifying the bug from Store to SQL, since it was fixed in the language layer.

        Show
        Knut Anders Hatlen added a comment - Thanks, Bryan! I've committed the patch to trunk with revision 903108. I also plan to back-port the fix to 10.5 before marking the issue as resolved. Since this bug was a regression in 10.3.1.4, the fix may be a candidate for back-porting all the way back to 10.3. I'm reclassifying the bug from Store to SQL, since it was fixed in the language layer.
        Hide
        Knut Anders Hatlen added a comment -

        Merged fix to 10.5 and committed revision 904472.

        Show
        Knut Anders Hatlen added a comment - Merged fix to 10.5 and committed revision 904472.
        Hide
        Kathey Marsden added a comment -

        Reopen to backport to 10.3

        Show
        Kathey Marsden added a comment - Reopen to backport to 10.3
        Hide
        Kathey Marsden added a comment -

        ported fix to 10.4 with the following revision which does not show up in subversion comments because the comment was for some reason truncated on the initial checkin.
        ----------------------------------------------------------------------
        r1085551 | kmarsden | 2011-03-25 13:33:53 -0700 (Fri, 25 Mar 2011) | 5 lines

        DERBY-4488 Nullpointer when performing INSERT INTO

        merge revision 903108 from trunk
        Contributed by Knut Anders Hatlen

        Show
        Kathey Marsden added a comment - ported fix to 10.4 with the following revision which does not show up in subversion comments because the comment was for some reason truncated on the initial checkin. ---------------------------------------------------------------------- r1085551 | kmarsden | 2011-03-25 13:33:53 -0700 (Fri, 25 Mar 2011) | 5 lines DERBY-4488 Nullpointer when performing INSERT INTO merge revision 903108 from trunk Contributed by Knut Anders Hatlen
        Hide
        Knut Anders Hatlen added a comment -

        [bulk update] Close all resolved issues that haven't been updated for more than one year.

        Show
        Knut Anders Hatlen added a comment - [bulk update] Close all resolved issues that haven't been updated for more than one year.

          People

          • Assignee:
            Knut Anders Hatlen
            Reporter:
            Huib
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development