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.



Reply via email to