use of java.sql.BatchUpdateException in project mssql-jdbc by Microsoft.
the class SQLServerPreparedStatement method executeBatch.
public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQLTimeoutException {
loggerExternal.entering(getClassNameLogging(), "executeBatch");
if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
checkClosed();
discardLastExecutionResults();
int[] updateCounts;
if (batchParamValues == null)
updateCounts = new int[0];
else
try {
// OUT or INOUT are present, the entire batch fails.
for (Parameter[] paramValues : batchParamValues) {
for (Parameter paramValue : paramValues) {
if (paramValue.isOutput()) {
throw new BatchUpdateException(SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null);
}
}
}
PrepStmtBatchExecCmd batchCommand = new PrepStmtBatchExecCmd(this);
executeStatement(batchCommand);
updateCounts = new int[batchCommand.updateCounts.length];
for (int i = 0; i < batchCommand.updateCounts.length; ++i) updateCounts[i] = (int) batchCommand.updateCounts[i];
// Transform the SQLException into a BatchUpdateException with the update counts.
if (null != batchCommand.batchException) {
throw new BatchUpdateException(batchCommand.batchException.getMessage(), batchCommand.batchException.getSQLState(), batchCommand.batchException.getErrorCode(), updateCounts);
}
} finally {
batchParamValues = null;
}
loggerExternal.exiting(getClassNameLogging(), "executeBatch", updateCounts);
return updateCounts;
}
use of java.sql.BatchUpdateException in project openmrs-core by openmrs.
the class DuplicateEncounterRoleNameChangeSet method execute.
/**
* Method to perform validation and resolution of duplicate EncounterRole names
*/
@Override
public void execute(Database database) throws CustomChangeException {
JdbcConnection connection = (JdbcConnection) database.getConnection();
Map<String, HashSet<Integer>> duplicates = new HashMap<>();
Statement stmt = null;
PreparedStatement pStmt = null;
ResultSet rs = null;
Boolean initialAutoCommit = null;
try {
initialAutoCommit = connection.getAutoCommit();
// set auto commit mode to false for UPDATE action
connection.setAutoCommit(false);
stmt = connection.createStatement();
rs = stmt.executeQuery("SELECT * FROM encounter_role INNER JOIN (SELECT name FROM encounter_role GROUP BY name HAVING count(name) > 1) dup ON encounter_role.name = dup.name");
Integer id;
String name;
while (rs.next()) {
id = rs.getInt("encounter_role_id");
name = rs.getString("name");
if (duplicates.get(name) == null) {
HashSet<Integer> results = new HashSet<>();
results.add(id);
duplicates.put(name, results);
} else {
HashSet<Integer> results = duplicates.get(name);
results.add(id);
}
}
for (Object o : duplicates.entrySet()) {
Map.Entry pairs = (Map.Entry) o;
HashSet values = (HashSet) pairs.getValue();
List<Integer> ids = new ArrayList<Integer>(values);
int duplicateNameId = 1;
for (int i = 1; i < ids.size(); i++) {
String newName = pairs.getKey() + "_" + duplicateNameId;
List<List<Object>> duplicateResult;
boolean duplicateName;
Connection con = DatabaseUpdater.getConnection();
do {
String sqlValidatorString = "select * from encounter_role where name = '" + newName + "'";
duplicateResult = DatabaseUtil.executeSQL(con, sqlValidatorString, true);
if (!duplicateResult.isEmpty()) {
duplicateNameId += 1;
newName = pairs.getKey() + "_" + duplicateNameId;
duplicateName = true;
} else {
duplicateName = false;
}
} while (duplicateName);
pStmt = connection.prepareStatement("update encounter_role set name = ?, changed_by = ?, date_changed = ? where encounter_role_id = ?");
if (!duplicateResult.isEmpty()) {
pStmt.setString(1, newName);
}
pStmt.setString(1, newName);
pStmt.setInt(2, DatabaseUpdater.getAuthenticatedUserId());
Calendar cal = Calendar.getInstance();
Date date = new Date(cal.getTimeInMillis());
pStmt.setDate(3, date);
pStmt.setInt(4, ids.get(i));
duplicateNameId += 1;
pStmt.executeUpdate();
}
}
} catch (BatchUpdateException e) {
log.warn("Error generated while processsing batch insert", e);
try {
log.debug("Rolling back batch", e);
connection.rollback();
} catch (Exception rbe) {
log.warn("Error generated while rolling back batch insert", e);
}
// marks the changeset as a failed one
throw new CustomChangeException("Failed to update one or more duplicate EncounterRole names", e);
} catch (Exception e) {
throw new CustomChangeException(e);
} finally {
// set auto commit to its initial state
try {
connection.commit();
if (initialAutoCommit != null) {
connection.setAutoCommit(initialAutoCommit);
}
} catch (DatabaseException e) {
log.warn("Failed to set auto commit to ids initial state", e);
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.warn("Failed to close the resultset object");
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
log.warn("Failed to close the select statement used to identify duplicate EncounterRole object names");
}
}
if (pStmt != null) {
try {
pStmt.close();
} catch (SQLException e) {
log.warn("Failed to close the prepared statement used to update duplicate EncounterRole object names");
}
}
}
}
use of java.sql.BatchUpdateException in project mssql-jdbc by Microsoft.
the class BatchExecuteWithErrorsTest method Repro47239.
/**
* Batch test
*
* @throws SQLException
*/
@Test
@DisplayName("Batch Test")
public void Repro47239() throws SQLException {
String tableN = RandomUtil.getIdentifier("t_Repro47239");
final String tableName = AbstractSQLGenerator.escapeIdentifier(tableN);
final String insertStmt = "INSERT INTO " + tableName + " VALUES (999, 'HELLO', '4/12/1994')";
final String error16 = "RAISERROR ('raiserror level 16',16,42)";
final String select = "SELECT 1";
final String dateConversionError = "insert into " + tableName + " values (999999, 'Hello again', 'asdfasdf')";
String warning;
String error;
String severe;
con = DriverManager.getConnection(connectionString);
if (DBConnection.isSqlAzure(con)) {
// SQL Azure will throw exception for "raiserror WITH LOG", so the following RAISERROR statements have not "with log" option
warning = "RAISERROR ('raiserror level 4',4,1)";
error = "RAISERROR ('raiserror level 11',11,1)";
// On SQL Azure, raising FATAL error by RAISERROR() is not supported and there is no way to
// cut the current connection by a statement inside a SQL batch.
// Details: Although one can simulate a fatal error (that cuts the connections) by dropping the database,
// this simulation cannot be written entirely in TSQL (because it needs a new connection),
// and thus it cannot be put into a TSQL batch and it is useless here.
// So we have to skip the last scenario of this test case, i.e. "Test Severe (connection-closing) errors"
// It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best test coverage.
// this is a dummy statement that never being executed on SQL Azure
severe = "--Not executed when testing against SQL Azure";
} else {
warning = "RAISERROR ('raiserror level 4',4,1) WITH LOG";
error = "RAISERROR ('raiserror level 11',11,1) WITH LOG";
severe = "RAISERROR ('raiserror level 20',20,1) WITH LOG";
}
con.close();
int[] actualUpdateCounts;
int[] expectedUpdateCounts;
String actualExceptionText;
// SQL Server 2005 driver
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
} catch (ClassNotFoundException e1) {
fail(e1.toString());
}
Connection conn = DriverManager.getConnection(connectionString);
Statement stmt = conn.createStatement();
try {
stmt.executeUpdate("drop table " + tableName);
} catch (Exception ignored) {
}
stmt.executeUpdate("create table " + tableName + " (c1_int int, c2_varchar varchar(20), c3_date datetime, c4_int int identity(1,1) primary key)");
// Regular Statement batch update
expectedUpdateCounts = new int[] { 1, -2, 1, -2, 1, -2 };
Statement batchStmt = conn.createStatement();
batchStmt.addBatch(insertStmt);
batchStmt.addBatch(warning);
batchStmt.addBatch(insertStmt);
batchStmt.addBatch(warning);
batchStmt.addBatch(insertStmt);
batchStmt.addBatch(warning);
try {
actualUpdateCounts = batchStmt.executeBatch();
actualExceptionText = "";
} catch (BatchUpdateException bue) {
actualUpdateCounts = bue.getUpdateCounts();
actualExceptionText = bue.getMessage();
if (log.isLoggable(Level.FINE)) {
log.fine("BatchUpdateException occurred. Message:" + actualExceptionText);
}
} finally {
batchStmt.close();
}
if (log.isLoggable(Level.FINE)) {
log.fine("UpdateCounts:");
}
for (int updateCount : actualUpdateCounts) {
log.fine("" + updateCount + ",");
}
log.fine("");
assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), "Test interleaved inserts and warnings");
expectedUpdateCounts = new int[] { -3, 1, 1, 1 };
stmt.addBatch(error);
stmt.addBatch(insertStmt);
stmt.addBatch(insertStmt);
stmt.addBatch(insertStmt);
try {
actualUpdateCounts = stmt.executeBatch();
actualExceptionText = "";
} catch (BatchUpdateException bue) {
actualUpdateCounts = bue.getUpdateCounts();
actualExceptionText = bue.getMessage();
}
log.fine("UpdateCounts:");
for (int updateCount : actualUpdateCounts) {
log.fine("" + updateCount + ",");
}
log.fine("");
assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), "Test error followed by inserts");
// 50280
expectedUpdateCounts = new int[] { 1, -3 };
stmt.addBatch(insertStmt);
stmt.addBatch(error16);
try {
actualUpdateCounts = stmt.executeBatch();
actualExceptionText = "";
} catch (BatchUpdateException bue) {
actualUpdateCounts = bue.getUpdateCounts();
actualExceptionText = bue.getMessage();
}
for (int updateCount : actualUpdateCounts) {
log.fine("" + updateCount + ",");
}
log.fine("");
assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), "Test insert followed by non-fatal error (50280)");
// Test "soft" errors
conn.setAutoCommit(false);
stmt.addBatch(select);
stmt.addBatch(insertStmt);
stmt.addBatch(select);
stmt.addBatch(insertStmt);
try {
stmt.executeBatch();
assertEquals(true, false, "Soft error test: executeBatch unexpectedly succeeded");
} catch (BatchUpdateException bue) {
assertEquals("A result set was generated for update.", bue.getMessage(), "Soft error test: wrong error message in BatchUpdateException");
assertEquals(Arrays.equals(bue.getUpdateCounts(), new int[] { -3, 1, -3, 1 }), true, "Soft error test: wrong update counts in BatchUpdateException");
}
conn.rollback();
// Defect 128801: Rollback (with conversion error) should throw SQLException
stmt.addBatch(dateConversionError);
stmt.addBatch(insertStmt);
stmt.addBatch(insertStmt);
stmt.addBatch(insertStmt);
try {
stmt.executeBatch();
} catch (BatchUpdateException bue) {
assertThat(bue.getMessage(), containsString("Syntax error converting date"));
// CTestLog.CompareStartsWith(bue.getMessage(), "Syntax error converting date", "Transaction rollback with conversion error threw wrong
// BatchUpdateException");
} catch (SQLException e) {
assertThat(e.getMessage(), containsString("Conversion failed when converting date"));
// CTestLog.CompareStartsWith(e.getMessage(), "Conversion failed when converting date", "Transaction rollback with conversion error threw
// wrong SQLException");
}
conn.setAutoCommit(true);
// It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best test coverage.
if (!DBConnection.isSqlAzure(conn)) {
// Test Severe (connection-closing) errors
stmt.addBatch(error);
stmt.addBatch(insertStmt);
stmt.addBatch(warning);
// TODO Removed until ResultSet refactoring task (45832) is complete.
// stmt.addBatch(select); // error: select not permitted in batch
stmt.addBatch(insertStmt);
stmt.addBatch(severe);
stmt.addBatch(insertStmt);
stmt.addBatch(insertStmt);
try {
stmt.executeBatch();
assertEquals(false, true, "Test fatal errors batch execution succeeded (should have failed)");
} catch (BatchUpdateException bue) {
assertEquals(false, true, "Test fatal errors returned BatchUpdateException rather than SQLException");
} catch (SQLException e) {
actualExceptionText = e.getMessage();
if (actualExceptionText.endsWith("reset")) {
assertTrue(actualExceptionText.equalsIgnoreCase("Connection reset"), "Test fatal errors");
} else {
assertTrue(actualExceptionText.equalsIgnoreCase("raiserror level 20"), "Test fatal errors");
}
}
}
try {
stmt.executeUpdate("drop table " + tableName);
} catch (Exception ignored) {
}
stmt.close();
conn.close();
}
use of java.sql.BatchUpdateException in project mssql-jdbc by Microsoft.
the class PreparedStatementTest method testStatementPooling.
/**
* Test handling of statement pooling for prepared statements.
*
* @throws SQLException
*/
@Test
@Tag("slow")
public void testStatementPooling() throws SQLException {
// Test % handle re-use
try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) {
String query = String.format("/*statementpoolingtest_re-use_%s*/SELECT TOP(1) * FROM sys.tables;", UUID.randomUUID().toString());
con.setStatementPoolingCacheSize(10);
boolean[] prepOnFirstCalls = { false, true };
for (boolean prepOnFirstCall : prepOnFirstCalls) {
con.setEnablePrepareOnFirstPreparedStatementCall(prepOnFirstCall);
int[] queryCounts = { 10, 20, 30, 40 };
for (int queryCount : queryCounts) {
String[] queries = new String[queryCount];
for (int i = 0; i < queries.length; ++i) {
queries[i] = String.format("%s--%s--%s--%s", query, i, queryCount, prepOnFirstCall);
}
int testsWithHandleReuse = 0;
final int testCount = 500;
for (int i = 0; i < testCount; ++i) {
Random random = new Random();
int queryNumber = random.nextInt(queries.length);
try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(queries[queryNumber])) {
pstmt.execute();
// Grab handle-reuse before it would be populated if initially created.
if (0 < pstmt.getPreparedStatementHandle())
testsWithHandleReuse++;
// Make sure handle is updated.
pstmt.getMoreResults();
}
}
System.out.println(String.format("Prep on first call: %s Query count:%s: %s of %s (%s)", prepOnFirstCall, queryCount, testsWithHandleReuse, testCount, (double) testsWithHandleReuse / (double) testCount));
}
}
}
try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) {
// Test behvaior with statement pooling.
con.setStatementPoolingCacheSize(10);
this.executeSQL(con, "IF NOT EXISTS (SELECT * FROM sys.messages WHERE message_id = 99586) EXEC sp_addmessage 99586, 16, 'Prepared handle GAH!';");
// Test with missing handle failures (fake).
this.executeSQL(con, "CREATE TABLE #update1 (col INT);INSERT #update1 VALUES (1);");
this.executeSQL(con, "CREATE PROC #updateProc1 AS UPDATE #update1 SET col += 1; IF EXISTS (SELECT * FROM #update1 WHERE col % 5 = 0) RAISERROR(99586,16,1);");
try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement("#updateProc1")) {
for (int i = 0; i < 100; ++i) {
try {
assertSame(1, pstmt.executeUpdate());
} catch (SQLException e) {
// Since the original "Could not find prepared statement with handle" error does not terminate the execution after it.
if (!e.getMessage().contains("Prepared handle GAH")) {
throw e;
}
}
}
}
// although executeUpdate() throws exception, update operation should be executed successfully.
try (ResultSet rs = con.createStatement().executeQuery("select * from #update1")) {
rs.next();
assertSame(101, rs.getInt(1));
}
// Test batching with missing handle failures (fake).
this.executeSQL(con, "IF NOT EXISTS (SELECT * FROM sys.messages WHERE message_id = 99586) EXEC sp_addmessage 99586, 16, 'Prepared handle GAH!';");
this.executeSQL(con, "CREATE TABLE #update2 (col INT);INSERT #update2 VALUES (1);");
this.executeSQL(con, "CREATE PROC #updateProc2 AS UPDATE #update2 SET col += 1; IF EXISTS (SELECT * FROM #update2 WHERE col % 5 = 0) RAISERROR(99586,16,1);");
try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement("#updateProc2")) {
for (int i = 0; i < 100; ++i) {
pstmt.addBatch();
}
int[] updateCounts = null;
try {
updateCounts = pstmt.executeBatch();
} catch (BatchUpdateException e) {
// Since the original "Could not find prepared statement with handle" error does not terminate the execution after it.
if (!e.getMessage().contains("Prepared handle GAH")) {
throw e;
}
}
// since executeBatch() throws exception, it does not return anthing. So updateCounts is still null.
assertSame(null, updateCounts);
// although executeBatch() throws exception, update operation should be executed successfully.
try (ResultSet rs = con.createStatement().executeQuery("select * from #update2")) {
rs.next();
assertSame(101, rs.getInt(1));
}
}
}
try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) {
// Test behvaior with statement pooling.
con.setDisableStatementPooling(false);
con.setStatementPoolingCacheSize(10);
String lookupUniqueifier = UUID.randomUUID().toString();
String query = String.format("/*statementpoolingtest_%s*/SELECT * FROM sys.tables;", lookupUniqueifier);
// Execute statement first, should create cache entry WITHOUT handle (since sp_executesql was used).
try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) {
// sp_executesql
pstmt.execute();
// Make sure handle is updated.
pstmt.getMoreResults();
assertSame(0, pstmt.getPreparedStatementHandle());
}
// Execute statement again, should now create handle.
int handle = 0;
try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) {
// sp_prepexec
pstmt.execute();
// Make sure handle is updated.
pstmt.getMoreResults();
handle = pstmt.getPreparedStatementHandle();
assertNotSame(0, handle);
}
// Execute statement again and verify same handle was used.
try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) {
// sp_execute
pstmt.execute();
// Make sure handle is updated.
pstmt.getMoreResults();
assertNotSame(0, pstmt.getPreparedStatementHandle());
assertSame(handle, pstmt.getPreparedStatementHandle());
}
// Execute new statement with different SQL text and verify it does NOT get same handle (should now fall back to using sp_executesql).
SQLServerPreparedStatement outer = null;
try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query + ";")) {
outer = pstmt;
// sp_executesql
pstmt.execute();
// Make sure handle is updated.
pstmt.getMoreResults();
assertSame(0, pstmt.getPreparedStatementHandle());
assertNotSame(handle, pstmt.getPreparedStatementHandle());
}
try {
System.out.println(outer.getPreparedStatementHandle());
fail("Error for invalid use of getPreparedStatementHandle() after statement close expected.");
} catch (Exception e) {
// Good!
}
}
}
use of java.sql.BatchUpdateException in project openmrs-core by openmrs.
the class ConceptValidatorChangeSet method runBatchUpdate.
/**
* Executes all the changes to the concept names as a batch update.
*
* @param connection The database connection
*/
private void runBatchUpdate(JdbcConnection connection) {
PreparedStatement pStmt = null;
try {
connection.setAutoCommit(false);
pStmt = connection.prepareStatement("UPDATE concept_name SET locale = ?, concept_name_type = ?, locale_preferred = ?, voided = ?, date_voided = ?, void_reason = ?, voided_by = ? WHERE concept_name_id = ?");
Integer userId = DatabaseUpdater.getAuthenticatedUserId();
// is we have no authenticated user(for API users), set as Daemon
if (userId == null || userId < 1) {
userId = getInt(connection, "SELECT min(user_id) FROM users");
// leave it as null rather than setting it to 0
if (userId < 1) {
userId = null;
}
}
for (ConceptName conceptName : updatedConceptNames) {
pStmt.setString(1, conceptName.getLocale().toString());
pStmt.setString(2, (conceptName.getConceptNameType() != null) ? conceptName.getConceptNameType().toString() : null);
pStmt.setBoolean(3, conceptName.getLocalePreferred());
pStmt.setBoolean(4, conceptName.getVoided());
pStmt.setDate(5, conceptName.getVoided() ? new Date(System.currentTimeMillis()) : null);
pStmt.setString(6, conceptName.getVoidReason());
// "Not all databases allow for a non-typed Null to be sent to the backend", so we can't use setInt
pStmt.setObject(7, (conceptName.getVoided() && userId != null) ? userId : null, Types.INTEGER);
pStmt.setInt(8, conceptName.getConceptNameId());
pStmt.addBatch();
}
try {
int[] updateCounts = pStmt.executeBatch();
for (int updateCount : updateCounts) {
if (updateCount > -1) {
log.debug("Successfully executed: updateCount=" + updateCount);
} else if (updateCount == Statement.SUCCESS_NO_INFO) {
log.debug("Successfully executed; No Success info");
} else if (updateCount == Statement.EXECUTE_FAILED) {
log.warn("Failed to execute update");
}
}
log.debug("Committing updates...");
connection.commit();
} catch (BatchUpdateException be) {
log.warn("Error generated while processsing batch update", be);
int[] updateCounts = be.getUpdateCounts();
for (int updateCount : updateCounts) {
if (updateCount > -1) {
log.warn("Executed with exception: updateCount=" + updateCount);
} else if (updateCount == Statement.SUCCESS_NO_INFO) {
log.warn("Executed with exception; No Success info");
} else if (updateCount == Statement.EXECUTE_FAILED) {
log.warn("Failed to execute update with exception");
}
}
try {
log.warn("Rolling back batch", be);
connection.rollback();
} catch (Exception rbe) {
log.warn("Error generated while rolling back batch update", be);
}
}
} catch (SQLException | DatabaseException e) {
log.warn("Error generated", e);
} finally {
// reset to auto commit mode
try {
connection.setAutoCommit(true);
} catch (DatabaseException e) {
log.warn("Failed to reset auto commit back to true", e);
}
if (pStmt != null) {
try {
pStmt.close();
} catch (SQLException e) {
log.warn("Failed to close the prepared statement object");
}
}
}
}
Aggregations