mirror of https://github.com/apache/openjpa.git
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:
parent
3d8748c427
commit
a4bf964c08
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
Loading…
Reference in New Issue