diff --git a/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java b/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java index e7a9246dea..5906aee191 100644 --- a/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java +++ b/symmetric-client/src/main/java/org/jumpmind/symmetric/ClientSymmetricEngine.java @@ -373,6 +373,8 @@ protected static SqlTemplateSettings createSqlTemplateSettings(TypedProperties p settings.setReadStringsAsBytes(properties.is(ParameterConstants.JDBC_READ_STRINGS_AS_BYTES, false)); settings.setTreatBinaryAsLob(properties.is(ParameterConstants.TREAT_BINARY_AS_LOB_ENABLED, true)); settings.setRightTrimCharValues(properties.is(ParameterConstants.RIGHT_TRIM_CHAR_VALUES, false)); + settings.setAllowUpdatesWithResults(properties.is(ParameterConstants.ALLOW_UPDATES_WITH_RESULTS, false)); + LogSqlBuilder logSqlBuilder = new LogSqlBuilder(); logSqlBuilder.setLogSlowSqlThresholdMillis(properties.getInt(ParameterConstants.LOG_SLOW_SQL_THRESHOLD_MILLIS, 20000)); logSqlBuilder.setLogSqlParametersInline(properties.is(ParameterConstants.LOG_SQL_PARAMETERS_INLINE, true)); diff --git a/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java b/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java index d1688ed5b2..2ded96d4f9 100644 --- a/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java +++ b/symmetric-core/src/main/java/org/jumpmind/symmetric/common/ParameterConstants.java @@ -435,6 +435,8 @@ private ParameterConstants() { public final static String RIGHT_TRIM_CHAR_VALUES = "right.trim.char.values"; + public final static String ALLOW_UPDATES_WITH_RESULTS = "allow.updates.with.results"; + public final static String NODE_LOAD_ONLY = "load.only"; public final static String MYSQL_TINYINT_DDL_TO_BOOLEAN = "mysql.tinyint.ddl.to.boolean"; diff --git a/symmetric-core/src/main/resources/symmetric-default.properties b/symmetric-core/src/main/resources/symmetric-default.properties index 7f8b7b1a57..7980a859d0 100644 --- a/symmetric-core/src/main/resources/symmetric-default.properties +++ b/symmetric-core/src/main/resources/symmetric-default.properties @@ -2233,6 +2233,14 @@ treat.binary.as.lob.enabled=true # Tags: other right.trim.char.values=false +# When executing DML statements during data load, this controls whether executeUpdate or execute is used on the PreparedStatement. executeUpdate +# is used by default. execute() allows for unusual situations like when an application trigger generates a result set during an +# update statement. +# +# DatabaseOverridable: true +# Type: boolean +# Tags: other +allow.updates.with.results=false # This is the location the staging directory will be put. If it isn't set the staging directory will be located according to java.io.tmpdir. # diff --git a/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlTemplateSettings.java b/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlTemplateSettings.java index 452fba659e..5a5b07495d 100644 --- a/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlTemplateSettings.java +++ b/symmetric-db/src/main/java/org/jumpmind/db/sql/SqlTemplateSettings.java @@ -31,6 +31,7 @@ public class SqlTemplateSettings { protected int overrideIsolationLevel = -1; protected int resultSetType = java.sql.ResultSet.TYPE_FORWARD_ONLY; protected LogSqlBuilder logSqlBuilder; + protected boolean allowUpdatesWithResults = false; public SqlTemplateSettings() { } @@ -107,4 +108,12 @@ public void setRightTrimCharValues(boolean rightTrimCharValues) { this.rightTrimCharValues = rightTrimCharValues; } + public boolean isAllowUpdatesWithResults() { + return allowUpdatesWithResults; + } + + public void setAllowUpdatesWithResults(boolean allowUpdatesWithResults) { + this.allowUpdatesWithResults = allowUpdatesWithResults; + } + } diff --git a/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java b/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java index a49ec9813e..528873f4f0 100644 --- a/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java +++ b/symmetric-jdbc/src/main/java/org/jumpmind/db/sql/JdbcSqlTransaction.java @@ -329,18 +329,7 @@ public Integer execute(Connection con) throws SQLException { try { stmt = con.prepareStatement(sql); jdbcSqlTemplate.setValues(stmt, args, types, jdbcSqlTemplate.getLobHandler().getDefaultHandler()); - - long startTime = System.currentTimeMillis(); - boolean hasResults = stmt.execute(); - long endTime = System.currentTimeMillis(); - logSqlBuilder.logSql(log, sql, args, types, (endTime-startTime)); - - if (hasResults) { - rs = stmt.getResultSet(); - while (rs.next()) { - } - } - return stmt.getUpdateCount(); + return executePreparedUpdate(stmt, sql, args, types); } catch (SQLException e) { throw logSqlBuilder.logSqlAfterException(log, sql, args, e); } finally { @@ -468,17 +457,41 @@ public int addRow(Object marker, Object[] args, int[] argTypes) { rowsUpdated = flush(); } } else { - long start = System.currentTimeMillis(); - pstmt.execute(); - long end = System.currentTimeMillis(); - logSqlBuilder.logSql(log, psql, args, argTypes, (end-start)); - rowsUpdated = pstmt.getUpdateCount(); + rowsUpdated = executePreparedUpdate(pstmt, psql, args, argTypes); } } catch (SQLException ex) { throw jdbcSqlTemplate.translate(ex); } return rowsUpdated; } + + protected int executePreparedUpdate(PreparedStatement preparedStatement, String sql, Object[] args, int[] argTypes) throws SQLException { + int rowsUpdated = 0; + long start = System.currentTimeMillis(); + if (jdbcSqlTemplate.getSettings().isAllowUpdatesWithResults()) { + rowsUpdated = executeAllowingResults(preparedStatement); + } else { + rowsUpdated = preparedStatement.executeUpdate(); + } + long end = System.currentTimeMillis(); + logSqlBuilder.logSql(log, psql, args, argTypes, (end-start)); + return rowsUpdated; + } + + protected int executeAllowingResults(PreparedStatement preparedStatement) throws SQLException { + int rowsUpdated = 0; + boolean hasResultsFlag = preparedStatement.execute(); + int currentUpdateCount = preparedStatement.getUpdateCount(); + + while (hasResultsFlag || currentUpdateCount != -1) { + if (currentUpdateCount != -1) { + rowsUpdated += currentUpdateCount; + } + hasResultsFlag = preparedStatement.getMoreResults(); + currentUpdateCount = preparedStatement.getUpdateCount(); + } + return rowsUpdated; + } public List getUnflushedMarkers(boolean clear) { List ret = new ArrayList(markers);