OPENJPA-360 SQL FOR UPDATE OF incorrectly generated for DB2 UDB version8.1 or earlier and DB2 ISeries V5R3 or earlier.

These  DB2 version also require the "optimize for <n> row" clause appear before FOR UPDATE clause.
Due to this requirement, the OPTIMIZE clause will  appear before FOR UPDATE clause for all DB2 versions.
Also fixed the affected testcases.


git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@574464 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Catalina Wei 2007-09-11 05:32:37 +00:00
parent 3d8748c427
commit a4bf964c08
6 changed files with 88 additions and 113 deletions

View File

@ -50,12 +50,12 @@ public class DB2Dictionary
public String optimizeClause = "optimize for";
public String rowClause = "row";
protected int db2ServerType = 0;
protected static final int db2ISeriesV5R3OrEarlier = 1;
protected static final int db2UDBV81OrEarlier = 2;
protected static final int db2ZOSV8xOrLater = 3;
protected static final int db2UDBV82OrLater = 4;
protected static final int db2ISeriesV5R4OrLater = 5;
private static final String forUpdateOfClause = "FOR UPDATE OF";
public static final int db2ISeriesV5R3OrEarlier = 1;
public static final int db2UDBV81OrEarlier = 2;
public static final int db2ZOSV8xOrLater = 3;
public static final int db2UDBV82OrLater = 4;
public static final int db2ISeriesV5R4OrLater = 5;
private static final String forUpdate = "FOR UPDATE";
private static final String withRSClause = "WITH RS";
private static final String withRRClause = "WITH RR";
private static final String useKeepUpdateLockClause
@ -313,9 +313,12 @@ public class DB2Dictionary
* updateClause and isolationLevel hints
*/
protected String getForUpdateClause(JDBCFetchConfiguration fetch,
boolean forUpdate) {
boolean isForUpdate) {
int isolationLevel;
StringBuffer forUpdateString = new StringBuffer();
// For db2UDBV81OrEarlier and db2ISeriesV5R3OrEarlier:
// "optimize for" clause appears before "for update" clause.
StringBuffer forUpdateString = new StringBuffer(
getOptimizeClause(fetch));
try {
// Determine the isolationLevel; the fetch
// configuration data overrides the persistence.xml value
@ -324,16 +327,15 @@ public class DB2Dictionary
else
isolationLevel = conf.getTransactionIsolationConstant();
if (forUpdate) {
if (isForUpdate) {
switch(db2ServerType) {
case db2ISeriesV5R3OrEarlier:
case db2UDBV81OrEarlier:
if (isolationLevel ==
Connection.TRANSACTION_READ_UNCOMMITTED) {
forUpdateString.append(" ").append(withRSClause)
.append(" ").append(forUpdateOfClause);
} else
forUpdateString.append(" ").append(forUpdateOfClause);
if (isolationLevel == Connection.TRANSACTION_SERIALIZABLE)
forUpdateString.append(" ").append(forUpdateClause);
else
forUpdateString.append(" ").append(forUpdate)
.append(" ").append(withRSClause);
break;
case db2ZOSV8xOrLater:
case db2UDBV82OrLater:
@ -368,7 +370,7 @@ public class DB2Dictionary
return forUpdateString.toString();
}
public boolean isDB2UDBV82OrLater() throws SQLException {
public boolean isDB2UDBV82OrLater() {
boolean match = false;
if ((databaseProductVersion.indexOf("SQL") != -1
|| databaseProductName.indexOf("DB2/") != -1)
@ -377,8 +379,7 @@ public class DB2Dictionary
return match;
}
public boolean isDB2ZOSV8xOrLater()
throws SQLException {
public boolean isDB2ZOSV8xOrLater() {
boolean match = false;
if ((databaseProductVersion.indexOf("DSN") != -1
|| databaseProductName.indexOf("DB2/") == -1)
@ -387,8 +388,7 @@ public class DB2Dictionary
return match;
}
public boolean isDB2ISeriesV5R3OrEarlier()
throws SQLException {
public boolean isDB2ISeriesV5R3OrEarlier() {
boolean match = false;
if (databaseProductName.indexOf("AS") != -1
&& ((maj == 5 && min <=3) || maj < 5))
@ -396,8 +396,7 @@ public class DB2Dictionary
return match;
}
public boolean isDB2ISeriesV5R4OrLater()
throws SQLException {
public boolean isDB2ISeriesV5R4OrLater() {
boolean match = false;
if (databaseProductName.indexOf("AS") != -1
&& (maj >=6 || (maj == 5 && min >=4)))
@ -405,7 +404,7 @@ public class DB2Dictionary
return match;
}
public boolean isDB2UDBV81OrEarlier() throws SQLException {
public boolean isDB2UDBV81OrEarlier() {
boolean match = false;
if ((databaseProductVersion.indexOf("SQL") != -1
|| databaseProductName.indexOf("DB2/") != -1) &&
@ -465,17 +464,16 @@ public class DB2Dictionary
}
}
public SQLBuffer toSelect(Select sel, boolean forUpdate,
JDBCFetchConfiguration fetch) {
SQLBuffer buf = super.toSelect(sel, forUpdate, fetch);
if (sel.getExpectedResultCount() > 0) {
protected String getOptimizeClause(JDBCFetchConfiguration fetch) {
if (sel != null && sel.getExpectedResultCount() > 0) {
StringBuffer buf = new StringBuffer();
buf.append(" ").append(optimizeClause).append(" ")
.append(String.valueOf(sel.getExpectedResultCount()))
.append(" ").append(rowClause);
return buf.toString();
}
return buf;
return "";
}
public OpenJPAException newStoreException(String msg, SQLException[] causes,

View File

@ -325,6 +325,7 @@ public class DBDictionary
private Method _setBytes = null;
private Method _setString = null;
private Method _setCharStream = null;
protected transient Select sel = null;
public DBDictionary() {
fixedSizeTypeNameSet.addAll(Arrays.asList(new String[]{
@ -1988,6 +1989,7 @@ public class DBDictionary
*/
public SQLBuffer toSelect(Select sel, boolean forUpdate,
JDBCFetchConfiguration fetch) {
this.sel = sel;
sel.addJoinClassConditions();
boolean update = forUpdate && sel.getFromSelect() == null;
SQLBuffer select = getSelects(sel, false, update);
@ -2198,11 +2200,11 @@ public class DBDictionary
* updateClause and isolationLevel hints
*/
protected String getForUpdateClause(JDBCFetchConfiguration fetch,
boolean forUpdate) {
boolean isForUpdate) {
if (fetch != null && fetch.getIsolation() != -1) {
throw new InvalidStateException(_loc.get(
"isolation-level-config-not-supported", getClass().getName()));
} else if (forUpdate && !simulateLocking) {
} else if (isForUpdate && !simulateLocking) {
assertSupport(supportsSelectForUpdate, "SupportsSelectForUpdate");
return forUpdateClause;
} else {

View File

@ -81,37 +81,23 @@ public class TestIsolationLevelOverride
q.getResultList();
if (dict instanceof DB2Dictionary) {
if ((((DB2Dictionary) dict).getDb2ServerType() == 1)
|| (((DB2Dictionary) dict).getDb2ServerType()== 2)) {
int db2server = ((DB2Dictionary) dict).getDb2ServerType();
if (db2server == DB2Dictionary.db2ISeriesV5R3OrEarlier
|| db2server == DB2Dictionary.db2UDBV81OrEarlier) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.id, t0.booleanField, t0.byteField,"
+ " t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField, "
+ "t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE \\(t0.intField = \\?\\) "
+ " FOR UPDATE OF");
assertContainsSQL(" FOR UPDATE");
}
// it is DB2 v82 or later
else if ((((DB2Dictionary) dict).getDb2ServerType() == 3)
|| (((DB2Dictionary) dict).getDb2ServerType() == 4)) {
else if (db2server == DB2Dictionary.db2ZOSV8xOrLater
|| db2server == DB2Dictionary.db2UDBV82OrLater) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.id, t0.booleanField, t0.byteField,"
+ " t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField, "
+ "t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE \\(t0.intField = \\?\\) "
+ " FOR READ ONLY WITH RR USE AND KEEP "
assertContainsSQL(" FOR READ ONLY WITH RR USE AND KEEP "
+ "UPDATE LOCKS");
}
else if (((DB2Dictionary) dict).getDb2ServerType() == 5) {
else if (db2server == DB2Dictionary.db2ISeriesV5R4OrLater) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.id, t0.booleanField, t0.byteField,"
+ " t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField, "
+ "t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE \\(t0.intField = \\?\\) "
+ " FOR READ ONLY WITH RR USE AND KEEP EXCLUSIVE "
+ "LOCKS");
assertContainsSQL(" FOR READ ONLY WITH RR USE AND KEEP"
+ " EXCLUSIVE LOCKS");
}
else {
fail("OpenJPA currently only supports "
@ -124,37 +110,25 @@ public class TestIsolationLevelOverride
.setIsolation(IsolationLevel.SERIALIZABLE);
em.find(AllFieldTypes.class, 0);
if (dict instanceof DB2Dictionary ) {
if ((((DB2Dictionary) dict).getDb2ServerType() == 1)
|| (((DB2Dictionary) dict).getDb2ServerType()== 2)) {
int db2server = ((DB2Dictionary) dict).getDb2ServerType();
if (db2server == DB2Dictionary.db2ISeriesV5R3OrEarlier
|| db2server == DB2Dictionary.db2UDBV81OrEarlier) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.booleanField, t0.byteField, "
+ "t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField,"
+ " t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE t0.id = \\? "
+ " FOR UPDATE OF optimize for 1 row");
assertContainsSQL(" optimize for 1 row FOR UPDATE");
}
// it is DB2 v82 or later
else if ((((DB2Dictionary) dict).getDb2ServerType() == 3)
|| (((DB2Dictionary) dict).getDb2ServerType() == 4)) {
else if (db2server == DB2Dictionary.db2ZOSV8xOrLater
|| db2server == DB2Dictionary.db2UDBV82OrLater) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.booleanField, t0.byteField, "
+ "t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField,"
+ " t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE t0.id = \\? "
assertContainsSQL(" optimize for 1 row"
+ " FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS"
+ " optimize for 1 row");
);
}
else if (((DB2Dictionary) dict).getDb2ServerType() == 5) {
else if (db2server == DB2Dictionary.db2ISeriesV5R4OrLater) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.booleanField, t0.byteField, "
+ "t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField,"
+ " t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE t0.id = \\? "
assertContainsSQL(" optimize for 1 row"
+ " FOR READ ONLY WITH RR USE AND KEEP EXCLUSIVE"
+ " LOCKS optimize for 1 row");
+ " LOCKS");
}
else {
fail("OpenJPA currently only supports per-query"

View File

@ -81,22 +81,14 @@ public class TestOptimizeForClause
}
if (dict instanceof DB2Dictionary) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.id, t0.booleanField, t0.byteField," +
" t0.charField, t0.dateField, t0.doubleField, " +
"t0.floatField, t0.intField, t0.longField, " +
"t0.shortField, t0.stringField FROM AllFieldTypes " +
"t0 WHERE \\(t0.intField = \\?\\) optimize for 8 row");
assertContainsSQL(" optimize for 8 row");
}
}
else {
em.find(AllFieldTypes.class, 0);
if (dict instanceof DB2Dictionary ) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.booleanField, t0.byteField, " +
"t0.charField, t0.dateField, t0.doubleField, " +
"t0.floatField, t0.intField, t0.longField, " +
"t0.shortField, t0.stringField FROM AllFieldTypes" +
" t0 WHERE t0.id = \\? optimize for 1 row");
assertContainsSQL(" optimize for 1 row");
}
}

View File

@ -33,7 +33,14 @@ public class TestSelectForUpdateOverride
extends SQLListenerTestCase {
public void setUp() {
setUp(AllFieldTypes.class,
setUp(
// "openjpa.ConnectionDriverName",
// "org.apache.commons.dbcp.BasicDataSource",
"openjpa.ConnectionProperties",
"DriverClassName=com.ibm.db2.jcc.DB2Driver,Url=jdbc:db2:demodb"
,"openjpa.jdbc.SynchronizeMappings",
AllFieldTypes.class,
"openjpa.Optimistic", "false",
"openjpa.LockManager", "pessimistic",
"openjpa.ReadLockLevel", "none");
@ -57,37 +64,24 @@ public class TestSelectForUpdateOverride
em.find(AllFieldTypes.class, 0);
assertEquals(1, sql.size());
if (dict instanceof DB2Dictionary) {
if ((((DB2Dictionary) dict).getDb2ServerType() == 1)
|| (((DB2Dictionary) dict).getDb2ServerType()== 2)) {
int db2server = ((DB2Dictionary) dict).getDb2ServerType();
if (db2server == DB2Dictionary.db2ISeriesV5R3OrEarlier
|| db2server == DB2Dictionary.db2UDBV81OrEarlier) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.booleanField, t0.byteField, "
+ "t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField,"
+ " t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE t0.id = \\? "
+ " FOR UPDATE OF optimize for 1 row");
assertContainsSQL(" optimize for 1 row FOR UPDATE");
}
// it is DB2 v82 or later
else if ((((DB2Dictionary) dict).getDb2ServerType() == 3)
|| (((DB2Dictionary) dict).getDb2ServerType() == 4)) {
else if (db2server == DB2Dictionary.db2ZOSV8xOrLater
|| db2server == DB2Dictionary.db2UDBV82OrLater) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.booleanField, t0.byteField, "
+ "t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField,"
+ " t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE t0.id = \\? "
+ " FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS"
+ " optimize for 1 row");
assertContainsSQL(" optimize for 1 row"
+ " FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS");
}
else if (((DB2Dictionary) dict).getDb2ServerType() == 5) {
else if (db2server == DB2Dictionary.db2ISeriesV5R4OrLater) {
assertEquals(1, sql.size());
assertSQL("SELECT t0.booleanField, t0.byteField, "
+ "t0.charField, t0.dateField, t0.doubleField,"
+ " t0.floatField, t0.intField, t0.longField,"
+ " t0.shortField, t0.stringField FROM "
+ "AllFieldTypes t0 WHERE t0.id = \\? "
assertContainsSQL(" optimize for 1 row"
+ " FOR READ ONLY WITH RS USE AND KEEP EXCLUSIVE LOCKS"
+ " optimize for 1 row");
);
}
else {
fail("OpenJPA currently only supports per-query isolation "

View File

@ -78,6 +78,21 @@ public abstract class SQLListenerTestCase
+ " should not have been executed in SQL statements: " + sql);
}
/**
* Confirm that the executed SQL String contains the specified sqlExp.
*
* @param sqlExp the SQL expression. E.g., "SELECT BADCOLUMN .*"
*/
public void assertContainsSQL(String sqlExp) {
for (String statement : sql) {
if (statement.contains(sqlExp))
return;
}
fail("Expected regular expression <" + sqlExp + "> to be"
+ " contained in SQL statements: " + sql);
}
public class Listener
extends AbstractJDBCListener {