[ 
https://issues.apache.org/jira/browse/DERBY-3823?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13123247#comment-13123247
 ] 

Mamta A. Satoor commented on DERBY-3823:
----------------------------------------

Hi Dag, Thanks for working on this jira. I spent some time on it and your 
patch. I want to first recap my understanding of the issue and then share my 
thoughts on result set descriptor. Please let me know if my understanding of 
the jira or your concern about result set descriptor is incorrect

The problem seems to be that while getting the metadata by calling 
EmbedPreparedStatement.getMetaData(),we can run into NPE because activation 
class assoicated with the prepared statement might be NULL. Activation class is 
temporarily set to null while the prepared statement is getting 
recompiled(GenericStatement.prepMinion) and it is possible that during that 
temporary NULL activation stage, metadata code is trying to use the activation 
class. 

The proposed fix is to synchronize part of the logic in 
EmbedPreparedStatement.getMetaData(). The code that will be synchronized will 
be in a loop which will repreare the invalid prepared statement and get it's 
activation class. If the activation class is null, then we will stay in the 
while loop until we can grab a non-null activation class for the prepared 
statement. When we get out of the synchronization code, we can rest assured 
that activation is not null. After that, we pretty much follow the existing 
logic(with some code rework but the logic stays the same) in 
EmbedPreparedStatement.getMetaData() 

The existing code in EmbedPreparedStatement.getMetaData() code is as follows 
                                if (preparedStatement.isValid() == false) 
                                { 
                                        //need to revalidate the statement 
here, otherwise getResultDescription would 
                                        //still have info from previous valid 
statement 
                                        preparedStatement.rePrepare(lcc); 
                                        rMetaData = null; 
                                } 
                                //bug 4579 - gcDuringGetMetaData will be null 
if this is the first time 
                                //getMetaData call is made. 
                                //Second check - if the statement was 
revalidated since last getMetaData call, 
                                //then gcDuringGetMetaData wouldn't match with 
current generated class name 
                                if (gcDuringGetMetaData == null || 
gcDuringGetMetaData.equals(execp.getActivationClass().getName()) == false) 
                                { 
                                        rMetaData = null; 
                                        gcDuringGetMetaData = 
execp.getActivationClass().getName(); 
                                } 
The code above can run into npe in "gcDuringGetMetaData = 
execp.getActivationClass().getName();"  because getActivationClass() can be 
NULL. 

Part of the new suggested code is as follows 
+                synchronized(execp) { 
+                    // DERBY-3823 Some other thread may be repreparing 
+                    do { 
+                        while (!execp.upToDate()) { 
+                            execp.rePrepare(lcc); 
+                        } 
+ 
+                        currAc = execp.getActivationClass(); 
+                        resd = execp.getResultDescription(); 
+                    } while (currAc == null); 
+                } 
+ 
+                if (gcDuringGetMetaData == null) { 
+                    gcDuringGetMetaData = currAc.getName(); 
+                    rMetaData = null; 
+                } else { 
+                    if (!gcDuringGetMetaData.equals(currAc.getName())) { 
+                        rMetaData = null; 
+                        gcDuringGetMetaData = currAc.getName(); 
+                    } 
+                } 
+ 
With the new code, we can be certain that currAC is not null once we are 
outside the synchronized code and hence we should not run into NPE later when 
we are accessing currAC

Later on, EmbedPreparedStatement.getMetaData() gets the 
resultDescription(existing code to get the resultDescription is as follows 
ResultDescription resd = preparedStatement.getResultDescription();) and new 
code from Dag is as follows (resd = execp.getResultDescription();) 

The concern raised here by Dag is that the resultDescription may not match the 
newly reprepared statement's result description. I spent some time looking at 
the supporting code for getResultDescription and I think we might be ok with 
the result description being in sync with preapred statement. Following is what 
I found. Let me know if I might have missed something. 

getResultDescription() call from EmbedPreparedStatement.getMetaData() results 
into a call to GenericPreparedStatement.getResultDescription() which simply 
return local variable resultDesc. The resultDesc variable gets set by another 
method in the same class namely, GenericPreparedStatement.completeCompile. 

The completeCompile method has following comment 
                // get the result description (null for non-cursor statements) 
                // would we want to reuse an old resultDesc? 
                // or do we need to always replace in case this was select *? 
                resultDesc = qt.makeResultDescription(); 
It appears from the comment in completeCompile  above that we don't simply 
return the existing cached resultDesc(if it is not null). Instead, we actually 
reload the resultDesc everytime by calling qt.makeResultDescription(). Based on 
this, I think result description and prepared statement will not get out of 
sync. 
                
> NullPointerException in stress.multi test
> -----------------------------------------
>
>                 Key: DERBY-3823
>                 URL: https://issues.apache.org/jira/browse/DERBY-3823
>             Project: Derby
>          Issue Type: Bug
>          Components: Network Server
>    Affects Versions: 10.3.3.1, 10.7.1.1, 10.8.1.2
>            Reporter: Kathey Marsden
>              Labels: derby_triage10_5_2
>         Attachments: d3823-1.diff, derby.log
>
>
> I saw the following NPE in stress.multi running on 10.3 with derbyclient.
> java.lang.NullPointerException
>         at 
> org.apache.derby.impl.jdbc.EmbedPreparedStatement.getMetaData(Unknown
>  Source)
>         at org.apache.derby.impl.drda.DRDAConnThread.writeSQLDARD(Unknown 
> Source
> )
>         at org.apache.derby.impl.drda.DRDAConnThread.processCommands(Unknown 
> Sou
> rce)
>         at org.apache.derby.impl.drda.DRDAConnThread.run(Unknown Source)
> Cleanup action completed

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: 
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Reply via email to