I'm using derby 10.10.1.1 on windows and am encountering an issue when shutting 
down derby. After tracking down the problem, there seems to be a possible bug 
in the DRDAConnThread.java - before filing a jira item, I wanted to run this by 
the community for feedback.

The issue manifests itself when shutting down derby - under certain 
circumstances, a NullPointerException is thrown. Even worse - the exception is 
"hidden" since the handling of the exception itself throws an exception. This 
issue is not consistent in our tests and presents unpredictably - most likely a 
timing issue. While I don't have a firm grasp of the exact circumstances that 
cause the exception to be thrown, I believe it is clear that the handling of an 
exception is less than ideal and leads to this exception. Tracing through the 
code in DRDAConnThread.java will provide the best explanation:


1)      Code enters parseSECCHK (line 3117) to perform security check on a new 
session

2)      All security checks pass and control continues to line 3357 to the call
database.getConnection().resetFromPool();

3)      That method call generates an exception as derby is shutting down as 
follows:

java.sql.SQLNonTransientConnectionException: No current connection.

                at 
org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(SQLExceptionFactory40.java:77)

                at 
org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Util.java:148)

                at 
org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Util.java:164)

                at 
org.apache.derby.impl.jdbc.Util.noCurrentConnection(Util.java:333)

                at 
org.apache.derby.impl.jdbc.EmbedConnection.checkIfClosed(EmbedConnection.java:2375)

                at 
org.apache.derby.impl.jdbc.EmbedConnection.setupContextStack(EmbedConnection.java:2588)

                at 
org.apache.derby.impl.jdbc.EmbedConnection.resetFromPool(EmbedConnection.java:2983)

                at 
org.apache.derby.impl.drda.DRDAConnThread.parseSECCHK(DRDAConnThread.java:3357)

                at 
org.apache.derby.impl.drda.DRDAConnThread.parseDRDAConnection(DRDAConnThread.java:1198)

                at 
org.apache.derby.impl.drda.DRDAConnThread.processCommands(DRDAConnThread.java:998)

                at 
org.apache.derby.impl.drda.DRDAConnThread.run(DRDAConnThread.java:295)

Caused by: java.sql.SQLException: No current connection.

                at 
org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:42)

                at 
org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(SQLExceptionFactory40.java:125)

                at 
org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(SQLExceptionFactory40.java:71)

                ... 10 more

4)      This gets caught in line 3365 and calls handleException

5)      handleException attempts to inform the client of the exception and then 
calls closeSession and close on lines 8759 and 8760.

6)      closeSession() sets the session member variable to null. This is the 
crux of the issue

7)      After handleException is called, control returns to parseSECCHK() and 
continues to line 3374 (as all security checks passed).

8)      This line attempts to deference a member of session which has just been 
set to null by closeSession (in step 6) !!

9)      This will throw a NullPointerException which is passed up the stack and 
eventually caught and handled on line 320

10)   This handling calls handleException(e)

11)   handleException then calls sendUnexpectedException which attempts to 
dereference session once again on line 8794, which of course throws a 
NullPointerException.

12)   This NPE is never caught, thus handled by the uncaughtExceptionHandler 
which by default terminates the thread (note that this causes the above 
exception to step 3 to be "hidden" as only this exception is bubbled to the 
uncaughtExceptionHandler)

13)   However, we have set a default uncaughtExceptionHandler in our 
application which terminates on an uncaught exception. This is undesirable in 
this situation since we are only trying to terminate an embedded derby 
instance, but do not wish our application to terminate. However, this default 
behavior makes sense as an uncaught exception usually indicates a serious error.

Thus, it seems that the handling of an exception thrown by resetFromPool() 
needs work. I'm not sure what the "correct" behavior should be but throwing a 
DRDAProtocolException.newDisconnectException after handleException does "fix" 
the issue.

Shall I file a bug? Is there anything else I should be aware of?

Thanks

Yoel Spotts


Reply via email to