Skip to content

Commit

Permalink
OptimisticLockException does not give any details if batch is active (#…
Browse files Browse the repository at this point in the history
…1936)

* Fix for bug 35468915
Signed-off-by: Vaibhav Vishal <vaibhav.vishal@oracle.com>
  • Loading branch information
vavishal committed Oct 17, 2023
1 parent 5b39993 commit ae7f32c
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.eclipse.persistence.queries.ObjectLevelModifyQuery;
import org.eclipse.persistence.sessions.SessionProfiler;

import java.util.List;
import java.util.Vector;

/**
Expand All @@ -40,6 +41,7 @@ public class OptimisticLockException extends EclipseLinkException {
public final static int UNWRAPPING_OBJECT_DELETED_SINCE_LAST_READ = 5009;
public final static int OBJECT_CHANGED_SINCE_LAST_MERGE = 5010;
public final static int STATEMENT_NOT_EXECUTED_IN_BATCH = 5011;
public final static int STATEMENT_NOT_EXECUTED_IN_BATCH_WITH_PARAMETERS_LIST = 5012;

/**
* INTERNAL:
Expand Down Expand Up @@ -92,6 +94,14 @@ public static OptimisticLockException batchStatementExecutionFailure(){

}

public static OptimisticLockException batchStatementExecutionFailureWithParametersList(Object object, List<List> parameters, String queryString){
Object[] args = { object.getClass().getName(), parameters.toString(), queryString};

OptimisticLockException optimisticLockException = new OptimisticLockException(ExceptionMessageGenerator.buildMessage(OptimisticLockException.class, STATEMENT_NOT_EXECUTED_IN_BATCH_WITH_PARAMETERS_LIST, args));
optimisticLockException.setErrorCode(STATEMENT_NOT_EXECUTED_IN_BATCH_WITH_PARAMETERS_LIST);
return optimisticLockException;
}

public static OptimisticLockException mustHaveMappingWhenStoredInObject(Class<?> aClass) {
Object[] args = { aClass };

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand Down Expand Up @@ -33,7 +33,8 @@ public final class OptimisticLockExceptionResource extends ListResourceBundle {
{ "5008", "Must map the version lock field to java.sql.Timestamp when using Timestamp Locking" },
{ "5009", "The object of class [{1}] with primary key [{0}] cannot be unwrapped because it was deleted since it was last read." },
{ "5010", "The object [{0}] cannot be merged because it has changed or been deleted since it was last read. {2}Class> {1}" },
{ "5011", "One or more objects cannot be updated because it has changed or been deleted since it was last read" }
{ "5011", "One or more objects cannot be updated because it has changed or been deleted since it was last read" },
{ "5012", "One or more objects of class {0} with parameters list {1} cannot be updated for SQL query {2} because it has changed or been deleted since it was last read" }
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ public class DatabasePlatform extends DatasourcePlatform {
/** JSON support for ResultSet data retrieval. */
private transient volatile DatabaseJsonPlatform jsonPlatform;

/** This attribute will store the results from the batch execution */
private int[] executeBatchRowCounts;
/**
* Creates an instance of default database platform.
*/
Expand Down Expand Up @@ -308,6 +310,7 @@ public DatabasePlatform() {
this.useJDBCStoredProcedureSyntax = null;
this.storedProcedureTerminationToken = ";";
this.jsonPlatform = null;
this.executeBatchRowCounts = new int[0];
}

/**
Expand Down Expand Up @@ -1476,6 +1479,20 @@ public boolean isLobCompatibleWithDistinct() {
return true;
}

/**
* Returns the attribute containing the results from the batch execution
*/
public int[] getExecuteBatchRowCounts() {
return executeBatchRowCounts;
}

/**
* Sets the attribute containing the results from the batch execution
*/
public void setExecuteBatchRowCounts(int[] rowCounts) {
executeBatchRowCounts = rowCounts;
}

/**
* Builds a table of maximum numeric values keyed on java class. This is used for type testing but
* might also be useful to end users attempting to sanitize values.
Expand Down Expand Up @@ -2266,6 +2283,7 @@ public boolean supportsDeleteOnCascade() {
*/
public int executeBatch(Statement statement, boolean isStatementPrepared) throws java.sql.SQLException {
int[] rowCounts = statement.executeBatch();
setExecuteBatchRowCounts(rowCounts);
int rowCount = 0;
// Otherwise check if the row counts were returned.
for (int count : rowCounts) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.queries.ModifyQuery;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.DeleteObjectQuery;
import org.eclipse.persistence.queries.UpdateObjectQuery;
import org.eclipse.persistence.sessions.SessionProfiler;

import java.io.StringWriter;
Expand Down Expand Up @@ -155,7 +158,14 @@ private void executeBatch(AbstractSession session) {
Object rowCount = this.databaseAccessor.basicExecuteCall(this.previousCall, null, session, false);
if (this.previousCall.hasOptimisticLock() && rowCount instanceof Integer) {
if ((Integer)rowCount != 1) {
throw OptimisticLockException.batchStatementExecutionFailure();
Object object = null;
DatabaseQuery query = this.previousCall.getQuery();
if (query.isUpdateObjectQuery()) {
object = ((UpdateObjectQuery) query).getObject();
} else if (query.isDeleteObjectQuery()) {
object = ((DeleteObjectQuery) query).getObject();
}
throw OptimisticLockException.batchStatementExecutionFailureWithParametersList(object, parameters, query.getSQLString());
}
}
} finally {
Expand Down Expand Up @@ -186,7 +196,21 @@ private void executeBatch(AbstractSession session) {
this.databaseAccessor.writeStatementsCount++;

if (this.previousCall.hasOptimisticLock() && (this.executionCount != this.statementCount)) {
throw OptimisticLockException.batchStatementExecutionFailure();
int[] rowCounts = this.databaseAccessor.getPlatform().getExecuteBatchRowCounts();
List<List> failureParametersList = new ArrayList();
for (int i = 0; i < rowCounts.length; i++) {
if (rowCounts[i] != 1 ) {
failureParametersList.add(parameters.get(i));
}
}
Object object = null;
DatabaseQuery query = this.previousCall.getQuery();
if (query.isUpdateObjectQuery()) {
object = ((UpdateObjectQuery) query).getObject();
} else if (query.isDeleteObjectQuery()) {
object = ((DeleteObjectQuery) query).getObject();
}
throw OptimisticLockException.batchStatementExecutionFailureWithParametersList(object, failureParametersList, query.getSQLString());
}
} finally {
// Reset the batched sql string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,12 @@ public void testOPTIMISTICLock() {
}

assertNotNull("Proper exception not thrown when EntityManager.lock(object, OPTIMISTIC) is used.", optimisticLockException);
if (getDatabaseSession().getPlatform().usesBatchWriting()) {
Assert.assertTrue(optimisticLockException.getMessage(),
optimisticLockException.getMessage().contains("One or more objects of class"));
Assert.assertTrue(optimisticLockException.getMessage(),
optimisticLockException.getMessage().contains(Employee.class.getName()));
}
}
}

Expand Down

0 comments on commit ae7f32c

Please sign in to comment.