db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andreas Korneliussen <Andreas.Kornelius...@Sun.COM>
Subject Re: [jira] Updated: (DERBY-231) "FOR UPDATE" required for updatable result set to work
Date Thu, 03 Nov 2005 11:53:27 GMT
Daniel John Debrunner wrote:
> Bernt M. Johnsen wrote:
> 
> 
>>The patch looks sound. I'll commit when I have run derbyall and
>>experimented a bit on my own.
> 
> 
> 
> Is there an overview of what the patch does, any implementation details?
> 
Here:

The purpose of the patch is to allow a statement to be updatable without 
having to specify "FOR UPDATE".

My first look in the code indicated that I could do the fix by changing 
only one line of code:

org.apache.derby.impl.sql.compile.CursorNode.java, bind()

  if (updateMode == UNSPECIFIED) {
 >>    updateMode = determineUpdateMode(dataDictionary);
<<    updateMode = READ_ONLY;
  }

(UNSPECIFED here means that the statement does not contain "FOR UPDATE" 
or "FOR READ ONLY")

determineUpdateMode() checks if the statement can be updatable (i.e does 
not contain a join).

However, just changing this single line of code, would cause some 
side-effects if the user does not plan to do update:

a: The query plan would contain updateNodes, and it would probably not 
be optimal if using indexes.
b: The updateMode is used to determine the lockmode, so even a read-only 
  select would use updatelocks.

To prevent these side-effects, the idea is to provide the 
CursorNode.bind() method with some information about the concurrency 
mode for the statement. A JDBC Statement can be created with two modes 
of concurrency:  "ResultSet.CONCUR_READ_ONLY" or 
"ResultSet.CONCUR_UPDATABLE".  The default is ResultSet.CONCUR_READ_ONLY.

The CursorNode code has access to a LanguageConnectionContext and 
StatementContext. The patch makes information about the concurrency mode 
for the statement part of the StatementContext by using a flag, and it 
is passed down the layers whenever a statement is prepared.

This is done by adding a parameter to LanaguageConnectionContext. 
prepareInternalStatement(..) with the flag.

The CursorNode then uses the flag to determine the update mode:
CursorNode.java, bind()

if (updateMode == UNSPECIFIED) {
    if (getLanguageConnectionContext().
          getStatementContext().isForReadOnly()) {		
	updateMode = READ_ONLY;
  } else {
    updateMode = determineUpdateMode(dataDictionary);
  }
}

Statement caching:
Statements with identical SQL strings and identical schema on the same 
connection are cached in the GenericLangageConnectionContext 
(implementation of LanguageConnectionContext).  This is done by

a, in the prepareInternalStatement(..) method a GenericStatement object 
is created taking the parameters for schema and sql string.
b, This object is later used to lookup a GenericPreparedStatement from 
the cache.

Since now, a "SELECT * FROM T" can produce two different query plans, 
depending on the concurrency mode, the flag for concurrency mode is made 
part of the GenericStatement object, and its identiy (by modifying the 
equals() method). This ensures that the correct cached 
GenericPreparedStatement is looked up.

Side-effects and user impact:

The patch has been designed to not affect the current behaviour of 
"SELECT * FROM T FOR UPDATE" or "SELECT * FROM T FOR READ ONLY" 
statements regardless of concurrency mode.
It also provides the exact same behaviour as before if you do a "SELECT 
* FROM T" with concurrency mode CONCUR_READ_ONLY.

The patch only affect "SELECT * FROM T" if the concurrency mode is 
CONCUR_UPDATABLE, by making the the cursor updatable from the ResultSet, 
and with positioned updates.

-- Andreas


> Dan.
> 
> 


Mime
View raw message