db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Dag H. Wanvik (JIRA)" <derby-...@db.apache.org>
Subject [jira] Updated: (DERBY-1183) Client java.sql.ResultSet.getCursorName() does not return the correct cursor name for Statements after the first execution
Date Mon, 12 Jun 2006 22:24:31 GMT
     [ http://issues.apache.org/jira/browse/DERBY-1183?page=all ]

Dag H. Wanvik updated DERBY-1183:

    Attachment: derby-1183.stat

This is a first patch (derby-1183.diff) to solve this issue as well
as DERBY-1036; it seemed convenient to combine them.  I have run
derbyall, seeing only a bug in JitTest.java which is not related (diff
in derby version number). Please have a look at it.

Patch description:

The problem underlying DERBY-1185 is the following: A Statement (and by
inheritance, PreparedStatement and CallableStatement) will have a
cursor name associated with result set generated by the statement. Such
names are either set by the user (Statement#setCursorName) or assigned
by the system (aka "canned" cursor names in the client driver). In
either case, the user can get at the cursor name attached to a
statement by calling Resultset#getCursorName. This string can be used
to construct the SQL text of positioned update or delete statement.

Currently, when a cursor name is set on a statement, the following
actions are taken (Statement#setCursorName):

	1. The statement's string variable cursorName_ is set to the
           new string. This keeps track of the user cursor name set
           for this statement.

	2. A cache (clientCursorNameCache) of cursor names set by
	   the user for this connection is maintained to avoid having
	   any two identical cursor name for the same statement/result
	   set. When the cursor name is set, the check is performed
	   (2a) and the cache is updated with the new cursor name if
	   all is well (2b).

	If the statement (only applies for PreparedStatement and
	CallableStatement) already has a DRDA section (ch 7.14) 
	allocated, the following is also performed:

	3. A map (cursor name -> section) is updated.

	4. The section associated with this statement gets its
  	   variable clientCursorName set to the supplied cursor name.

For Statement, this association (steps 3 and 4) is performed at
statement execution time (inside flowExecute, just after the new
section is allocated for a query).

	5. Also in flowExecute (of Statement, PreparedStatement) the
	   cursor (user set or canned) is associated with the result
	   set (call to mapCursorNameToResultSet).

The symptom of this bug is that the cursor name set for a statement
seems to be lost after one execution of that statement, reverting to a
canned cursor name for executions 2..n.

This happens because the cursor name is actually reset as part of the
next execute on a statement object:

        6. Open result sets for a statement are closed when
	   flowExecute calls readCloseResultSets. During the closing
	   of a result set, ResultSet#markClosed calls
	   statement_.removeClientCursorNameFromCache, which in
	   addition to removing the user cursor name from the cache
	   also sets the statements cursorName_ to null, causing it
	   effectively to be forgotten.

Since #5 happens *after* #6 in flowExecute, the execution still works,
but with a canned cursor instead of the user named cursor (see

This "race condition" suggests deferring the setup of mappings and
insertion into the name cache till execution time (*after* the closing
of open result sets on this statement). When studying this I found
there was already a bug filed (DERBY-1036) which advises that we defer
the check of duplicates till execution time, so this patch fixes both
DERBY-1183 and DERBY-1036.

In the patch, Statement#setCursorName now only sets the string
variable cursorName_.

The patch also removes the resetting of cursorName_ in
removeClientCursorNameFromCache, so it won't be forgotten. It is still
removed from the cache when the result set is closed (and current maps

Furthermore, it moves #2, #3 and #4 till execution time (flowExecute).
Item #2a is performed at the start of flowExecute, so we can avoid
starting any protocol action if it turns out that we should not
start execution (duplicate name). The actions needed in
Statement#flowExecute and PreparedStatement#flowExecute are similar,
so I factored these out into the methods Statement#
checkForDuplicateCursorName and Statement#setupCursorNameCacheAndMappings.

Next, I removed code from getCursorName which redundantly performs #3
(now always handled at execute time).

CAVEAT: When working on understanding what goes on here, I found that
the Statement finalizer can lead to cursors being released; this is
part of the client side clean-up for statements that are not
explicitly closed (DERBY-210). This can sometimes lead to time
variability in canned cursor names in client driver tests which do not
close statements explicitly. If the canned cursor name occurs in the
canon file, we can see spurious diff due to this. I think we have seen
this in the past. Avoid it by closing statements or by naming the
cursors explicitly.

Finally, I removed work-around code in jdbcapi/checkDataSource.java
for derby-1036 and derby-1183 and updated masters to reflect that the
cursor names are no longer forgotten.

> Client java.sql.ResultSet.getCursorName() does not return the correct cursor name for
Statements after the first execution
> --------------------------------------------------------------------------------------------------------------------------
>          Key: DERBY-1183
>          URL: http://issues.apache.org/jira/browse/DERBY-1183
>      Project: Derby
>         Type: Bug

>   Components: JDBC
>     Versions:
>     Reporter: Kathey Marsden
>     Assignee: Dag H. Wanvik
>      Fix For:
>  Attachments: derby-1183.diff, derby-1183.stat
> For client, if the cursor name is set with java.sql.Statement.setCursorName() the name
set by the user only applies to the first execution.  Subsequent executions use the default
cursor name.  To reproduce run the progam below as follows:
> D>java -Dframework=DerbyNetClient GetCursorName
> alpha
> Apache Derby
> Apache Derby Network Client JDBC Driver
> rs.getCursorName():MyCursor
> rs.getCursorName():SQL_CURLH000C2
> With embedded it is ok:
> D>java  GetCursorName
> alpha
> Apache Derby
> Apache Derby Embedded JDBC Driver
> rs.getCursorName():MyCursor
> rs.getCursorName():MyCursor
> import java.sql.Connection;
> import java.sql.DatabaseMetaData;
> import java.sql.ResultSet;
> import java.sql.SQLException;
> import java.sql.Statement;
> import org.apache.derbyTesting.functionTests.util.TestUtil;
> class GetCursorName
> {
>     public static void main (String args [])throws Exception 
>     {
>     	testGetCursorName();
>     }
>     public static void testGetCursorName() throws SQLException
>     {
> 		Connection conn = TestUtil.getConnection("wombat","create=true");
> 		Statement stmt = null;
> 		ResultSet rs = null;
> 		DatabaseMetaData md = conn.getMetaData() ;
> 		System.out.println(md.getDatabaseProductVersion());
>         System.out.println(md.getDatabaseProductName());
>         System.out.println(md.getDriverName());
> 		stmt = conn.createStatement();
> 		// Setting the cursor name works for one execution ok.
> 		stmt.setCursorName("MyCursor");
> 		rs = stmt.executeQuery("select count(*) from sys.systables");
> 		System.out.println("rs.getCursorName():" + rs.getCursorName());
> 		rs.close();
> 		//Executing another query seems to clears the cursor name.
> 		// getCursorName() will print the default cursor name SQLXXX.
> 		rs = stmt.executeQuery("select count(*) from sys.systables");
> 		System.out.println("rs.getCursorName():" + rs.getCursorName());
> 		rs.close();
> 		stmt.close();
>         conn.close();
>       }
> }
> I noticed this bug when coverting the checkDataSource test for client.
> I will change that test to set the cursor name for each execution for client.

This message is automatically generated by JIRA.
If you think it was sent incorrectly contact one of the administrators:
For more information on JIRA, see:

View raw message