From 9e8e265d6ce4c198945b534489f02838870e8ae3 Mon Sep 17 00:00:00 2001 From: "David J. Wisneski" Date: Tue, 3 Apr 2007 19:34:59 +0000 Subject: [PATCH] changes for JIRA OPENJPA-182 git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@525252 13f79535-47bb-0310-9956-ffa450edef68 --- .../jdbc/sql/AbstractDB2Dictionary.java | 2 +- .../openjpa/jdbc/sql/DB2Dictionary.java | 243 +++++++++++++++++- 2 files changed, 239 insertions(+), 6 deletions(-) diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java index 5000e8ac3..5c3ff4bfc 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java @@ -52,7 +52,7 @@ public abstract class AbstractDB2Dictionary supportsLockingWithOrderClause = false; supportsLockingWithOuterJoin = false; supportsLockingWithInnerJoin = false; - supportsLockingWithSelectRange = false; + supportsLockingWithSelectRange = true; requiresAutoCommitForMetaData = true; requiresAliasForSubselect = true; diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java index 02a9d7137..bb6f3c10a 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java @@ -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 class DB2Dictionary 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 @@ public class DB2Dictionary 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 @@ public class DB2Dictionary } } + /** 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; } }