SQL provides capabilities for tuning of locking.  In the case of DB2
this involves setting the isolation level, update lock, result set
optimize set, etc.
JPA spec does not provide support for these concepts but does provide a rather
open ended setHint api.  It is our intent to make use this api so that
users can
sets these values without having to make use of OpenJPA specific apis
-- granted the hint name and value would be OpenJPA specific.
Furthermore, we are intending to support static SQL.  Static SQL is
extremely important in the enterprise environment for our larger
customers because (1) it provides better optimization of SQL and (2)
auditability and security over who access the data and how it is
accessed.    In the case of static SQL,  these hints would be defined
on a NamedQuery definition and not through runtime api.

On 4/3/07, Patrick Linskey <[EMAIL PROTECTED]> wrote:
I'm a little nervous about this change still. I don't like it that we're
adding yet another way to configure locking, especially since it seems
like the lock level settings should be sufficient (or nearly so) to
handle per-transaction / per-query lock levels.

I also still do not believe that isolationLevel should be a hint; it
seems more rule-like than hint-like.

To date, the OpenJPA model has not been to piggyback on the
Query.setHint() facilities for vendor-specific metadata, but rather to
use our OpenJPA extension classes (FetchPlan, etc.) to allow us to
convey more structured data to the kernel. I think that the isolation
level should probably be part of FetchPlan (or possibly JDBCFetchPlan),
and the update information should be obtainable from the FetchPlan's
read- and write-lock levels.

I don't think that we should rush this change in just so it's in 0.9.7;
we can always delay 0.9.7 if it's a must-have, or have a 0.9.8 that
follows soon thereafter. Generally-speaking, my experience is that once
code gets committed, it tends to not get cleaned up, so the argument
"let's get it in for the release and then fix it later" usually ends up
turning into "let's get it in for the release". This seems especially
true for a change like this, that is exposing new APIs (the hints).

Thoughts?

-Patrick

--
Patrick Linskey
BEA Systems, Inc.

_______________________________________________________________________
Notice:  This email message, together with any attachments, may contain
information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated
entities,  that may be confidential,  proprietary,  copyrighted  and/or
legally privileged, and is intended solely for the use of the individual
or entity named in this message. If you are not the intended recipient,
and have received this message in error, please immediately return this
by email and then delete it.

> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, April 03, 2007 12:35 PM
> To: open-jpa-commits@incubator.apache.org
> Subject: svn commit: r525252 - in
> /incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache
> /openjpa/jdbc/sql: AbstractDB2Dictionary.java DB2Dictionary.java
>
> Author: wisneskid
> Date: Tue Apr  3 12:34:59 2007
> New Revision: 525252
>
> URL: http://svn.apache.org/viewvc?view=rev&rev=525252
> Log:
> changes for JIRA OPENJPA-182
>
> Modified:
>
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/AbstractDB2Dictionary.java
>
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/DB2Dictionary.java
>
> Modified:
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/AbstractDB2Dictionary.java
> URL:
> http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-j
dbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java
?view=diff&rev=> 525252&r1=525251&r2=525252
> ==============================================================
> ================
> ---
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/AbstractDB2Dictionary.java (original)
> +++
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/AbstractDB2Dictionary.java Tue Apr  3 12:34:59 2007
> @@ -52,7 +52,7 @@
>          supportsLockingWithOrderClause = false;
>          supportsLockingWithOuterJoin = false;
>          supportsLockingWithInnerJoin = false;
> -        supportsLockingWithSelectRange = false;
> +        supportsLockingWithSelectRange = true;
>
>          requiresAutoCommitForMetaData = true;
>          requiresAliasForSubselect = true;
>
> Modified:
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/DB2Dictionary.java
> URL:
> http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-j
dbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java?view=di
ff&rev=525252&r1=> 525251&r2=525252
> ==============================================================
> ================
> ---
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/DB2Dictionary.java (original)
> +++
> incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/
openjpa/jdbc/sql/DB2Dictionary.java Tue Apr  3 12:34:59 2007
> @@ -15,13 +15,15 @@
>   */
>  package org.apache.openjpa.jdbc.sql;
>
> +import java.lang.reflect.Method;
>  import java.sql.Connection;
>  import java.sql.DatabaseMetaData;
>  import java.sql.SQLException;
>  import java.util.Arrays;
> -
> +import java.util.StringTokenizer;
>  import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
>  import org.apache.openjpa.jdbc.schema.Sequence;
> +import org.apache.openjpa.lib.log.Log;
>
>  /**
>   * Dictionary for IBM DB2 database.
> @@ -31,7 +33,18 @@
>
>      public String optimizeClause = "optimize for";
>      public String rowClause = "row";
> -
> +    private int db2ServerType = 0;
> +    private static final int  db2ISeriesV5R3AndEarlier = 1;
> +    private static final int db2UDBV81OrEarlier = 2;
> +    private static final int db2ZOSV8x = 3;
> +    private static final int db2UDBV82AndLater = 4;
> +    private static final int  db2ISeriesV5R4AndLater = 5;
> +     private static final String  forUpdateOfClause="FOR UPDATE OF";
> +    private static final String  withRSClause="WITH RS";
> +    private static final String  withRRClause="WITH RR";
> +    private static final String  useKeepUpdateLockClause=
> "USE AND KEEP UPDATE LOCKS";
> +    private static final String
> useKeepExclusiveLockClause="USE AND KEEP EXCLUSIVE LOCKS";
> +    private static final String  forReadOnlyClause = "FOR READ ONLY";
>      public DB2Dictionary() {
>          platform = "DB2";
>          validationSQL = "SELECT DISTINCT(CURRENT TIMESTAMP) FROM "
> @@ -170,6 +183,18 @@
>       if (isJDBC3(metaData)) {
>                       int maj = metaData.getDatabaseMajorVersion();
>               int min = metaData.getDatabaseMinorVersion();
> +
> +             // Determine the type of DB2 database
> +             if (isDB2ISeriesV5R3AndEarlier(metaData))
> +                 db2ServerType =db2ISeriesV5R3AndEarlier;
> +             else if (isDB2UDBV81OrEarlier(metaData,maj,min))
> +                 db2ServerType =db2UDBV81OrEarlier;
> +             else if (isDB2ZOSV8x(metaData,maj))
> +                 db2ServerType =db2ZOSV8x;
> +             else if (isDB2UDBV82AndLater(metaData,maj,min))
> +                 db2ServerType=db2UDBV82AndLater;
> +             else if (isDB2ISeriesV5R4AndLater(metaData))
> +                 db2ServerType=db2ISeriesV5R4AndLater;
>
>               if (maj >= 9 || (maj == 8 && min >= 2)) {
>                       supportsLockingWithMultipleTables = true;
> @@ -198,13 +223,221 @@
>          }
>      }
>
> +    /** Get the update clause for the query based on the
> +     * updateClause and isolationLevel hints
> +     */
> +    public String getForUpdateClause(JDBCFetchConfiguration
> fetch, boolean forUpdate) {
> +        String isolationLevel = null;
> +        Boolean updateClause = null;
> +        DatabaseMetaData metaData = null;
> +        StringBuffer forUpdateString = new StringBuffer();
> +        try {
> +            // Determine the update clause/isolationLevel the hint
> +            // overrides the persistence.xml value
> +            if (fetch != null &&
> fetch.getHint("openjpa.hint.updateClause")
> +                !=null )
> +                updateClause = (Boolean)fetch.
> +                getHint("openjpa.hint.updateClause");
> +            else
> +                updateClause = forUpdate;
> +            if (fetch != null
> &&fetch.getHint("openjpa.hint.isolationLevel")
> +                !=null )
> +                isolationLevel = (String)fetch.
> +                getHint("openjpa.hint.isolationLevel");
> +            else
> +                isolationLevel = conf.getTransactionIsolation();
> +            if (updateClause == false)
> +                //This sql is not for update so add FOR Read
> Only clause
> +                forUpdateString.append(" ").append(forReadOnlyClause)
> +                .append(" ");
> +            else if (updateClause == true){
> +
> +                switch(db2ServerType){
> +                case db2ISeriesV5R3AndEarlier:
> +                case db2UDBV81OrEarlier:
> +                    if (isolationLevel.equals("read-uncommitted"))
> +                        forUpdateString.append("
> ").append(withRSClause)
> +                        .append("
> ").append(forUpdateOfClause).append(" ");
> +                    else
> +                        forUpdateString.append("
> ").append(forUpdateOfClause)
> +                        .append(" ");
> +                    break;
> +                case db2ZOSV8x:
> +                case db2UDBV82AndLater:
> +                    if (isolationLevel.equals("serializable"))
> +                        forUpdateString.append("
> ").append(withRRClause)
> +                        .append(" ").append(useKeepUpdateLockClause)
> +                        .append(" ");
> +                    else
> +                        forUpdateString.append("
> ").append(withRSClause)
> +                        .append(" ").append(useKeepUpdateLockClause)
> +                        .append(" ");
> +                    break;
> +                case db2ISeriesV5R4AndLater:
> +                    if (isolationLevel.equals("serializable"))
> +                        forUpdateString.append("
> ").append(withRRClause)
> +                        .append("
> ").append(useKeepExclusiveLockClause)
> +                        .append(" ");
> +                    else
> +                        forUpdateString.append("
> ").append(withRSClause)
> +                        .append("
> ").append(useKeepExclusiveLockClause)
> +                        .append(" ");
> +                }
> +            }
> +        }
> +        catch (Exception e) {
> +            if (log.isTraceEnabled())
> +                log.error(e.toString(),e);
> +        }
> +        return forUpdateString.toString();
> +    }
> +
> +
> +    /** Override the DBDictionary toSelect to call
> getOptimizeClause and append
> +     *   to the select string
> +     */
> +    public SQLBuffer toSelect(SQLBuffer selects,
> JDBCFetchConfiguration fetch,
> +       SQLBuffer from, SQLBuffer where, SQLBuffer group,
> +       SQLBuffer having, SQLBuffer order,
> +       boolean distinct, boolean forUpdate, long start, long end,
> +       int expectedResultCount) {
> +       String forUpdateString = getForUpdateClause(fetch,forUpdate);
> +       SQLBuffer selString = toOperation(getSelectOperation(fetch),
> +            selects, from, where,
> +            group, having, order, distinct,
> +            forUpdate, start, end,forUpdateString);
> +        return selString;
> +    }
> +
> +    public boolean isDB2UDBV82AndLater(DatabaseMetaData
> metadata, int maj,
> +        int min) throws SQLException {
> +        boolean match = false;
> +        if
> (metadata.getDatabaseProductVersion().indexOf("SQL") != -1
> +            && ((maj ==8 && min >=2) ||(maj >=8)))
> +            match = true;
> +        return match;
> +    }
> +
> +    public boolean isDB2ZOSV8x(DatabaseMetaData metadata,int maj)
> +       throws SQLException {
> +       boolean match = false;
> +       if (metadata.getDatabaseProductVersion().indexOf("DSN") != -1
> +           && maj ==8 )
> +           match = true;
> +        return match;
> +    }
> +
> +    public boolean
> isDB2ISeriesV5R3AndEarlier(DatabaseMetaData metadata)
> +       throws SQLException {
> +       boolean match = false;
> +       if (metadata.getDatabaseProductVersion().indexOf("AS") != -1
> +           &&
> generateVersionNumber(metadata.getDatabaseProductVersion())
> +           <= 530 )
> +           match = true;
> +       return match;
> +    }
> +
> +    public boolean isDB2ISeriesV5R4AndLater(DatabaseMetaData
> metadata)
> +       throws SQLException {
> +       boolean match = false;
> +       if (metadata.getDatabaseProductVersion().indexOf("AS") != -1
> +           &&
> generateVersionNumber(metadata.getDatabaseProductVersion())
> +           >= 540 )
> +           match = true;
> +      return match;
> +    }
> +
> +    public boolean isDB2UDBV81OrEarlier(DatabaseMetaData
> metadata,int maj,
> +        int min) throws SQLException {
> +        boolean match = false;
> +        if
> (metadata.getDatabaseProductVersion().indexOf("SQL") != -1 &&
> +           ((maj ==8 && min <=1)|| maj <8 ))
> +            match = true;
> +        return match;
> +    }
> +
> +    /** Get the version number for the ISeries
> +     */
> +    protected  int generateVersionNumber(String versionString) {
> +        String s =
> versionString.substring(versionString.indexOf('V'));
> +        s = s.toUpperCase();
> +        int i = -1;
> +        StringTokenizer stringtokenizer = new
> StringTokenizer(s, "VRM", false);
> +        if (stringtokenizer.countTokens() == 3)
> +        {
> +            String s1 = stringtokenizer.nextToken();
> +            s1 = s1 + stringtokenizer.nextToken();
> +            s1 = s1 + stringtokenizer.nextToken();
> +            i = Integer.parseInt(s1);
> +        }
> +        return i;
> +    }
> +
> +
> +    /**
> +     * Override the toOperationMethod of DBDictionary to pass the
> +     * forUpdateString.
> +     */
> +    protected SQLBuffer toOperation(String op, SQLBuffer selects,
> +        SQLBuffer from, SQLBuffer where, SQLBuffer group,
> SQLBuffer having,
> +        SQLBuffer order, boolean distinct, boolean
> forUpdate, long start,
> +        long end,String forUpdateString) {
> +        SQLBuffer buf = new SQLBuffer(this);
> +        buf.append(op);
> +        boolean range = start != 0 || end != Long.MAX_VALUE;
> +        if (range && rangePosition == RANGE_PRE_DISTINCT)
> +            appendSelectRange(buf, start, end);
> +        if (distinct)
> +            buf.append(" DISTINCT");
> +        if (range && rangePosition == RANGE_POST_DISTINCT)
> +            appendSelectRange(buf, start, end);
> +        buf.append(" ").append(selects).append(" FROM
> ").append(from);
> +
> +        if (where != null && !where.isEmpty())
> +            buf.append(" WHERE ").append(where);
> +        if (group != null && !group.isEmpty())
> +            buf.append(" GROUP BY ").append(group);
> +        if (having != null && !having.isEmpty()) {
> +            assertSupport(supportsHaving, "SupportsHaving");
> +            buf.append(" HAVING ").append(having);
> +        }
> +        if (order != null && !order.isEmpty())
> +            buf.append(" ORDER BY ").append(order);
> +        if (range && rangePosition == RANGE_POST_SELECT)
> +            appendSelectRange(buf, start, end);
> +
> +        if (!simulateLocking ) {
> +            assertSupport(supportsSelectForUpdate,
> "SupportsSelectForUpdate");
> +            buf.append(" ").append(forUpdateString);
> +        }
> +        if (range && rangePosition == RANGE_POST_LOCK)
> +            appendSelectRange(buf, start, end);
> +        return buf;
> +    }
> +
>      public SQLBuffer toSelect(Select sel, boolean forUpdate,
>          JDBCFetchConfiguration fetch) {
> -        SQLBuffer buf = super.toSelect(sel, forUpdate, fetch);
> +        sel.addJoinClassConditions();
> +        boolean update = forUpdate && sel.getFromSelect() == null;
> +        SQLBuffer select = getSelects(sel, false, update);
> +        SQLBuffer ordering = null;
> +        if (!sel.isAggregate() || sel.getGrouping() != null)
> +            ordering = sel.getOrdering();
> +        SQLBuffer from;
> +        if (sel.getFromSelect() != null)
> +            from = getFromSelect(sel, forUpdate);
> +        else
> +            from = getFrom(sel, update);
> +        SQLBuffer where = getWhere(sel, update);
> +        String forUpdateString = getForUpdateClause(fetch,forUpdate);
> +        SQLBuffer buf =
> toOperation(getSelectOperation(fetch), select,
> +            from, where,sel.getGrouping(), sel.getHaving(),
> ordering,
> +            sel.isDistinct(), forUpdate, sel.getStartIndex(),
> +            sel.getEndIndex(),forUpdateString);
>          if (sel.getExpectedResultCount() > 0)
>              buf.append(" ").append(optimizeClause).append(" ").
> -                append(String.valueOf(sel.getExpectedResultCount())).
> -                append(" ").append(rowClause);
> +            append(String.valueOf(sel.getExpectedResultCount())).
> +            append(" ").append(rowClause);
>          return buf;
>      }
>  }
>
>
>

Notice:  This email message, together with any attachments, may contain 
information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated 
entities,  that may be confidential,  proprietary,  copyrighted  and/or legally 
privileged, and is intended solely for the use of the individual or entity 
named in this message. If you are not the intended recipient, and have received 
this message in error, please immediately return this by email and then delete 
it.

Reply via email to