blob: c4171bb31bddc5f8ea9a628b0eed18ae2db34a14 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.lib.jdbc;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.BatchUpdateException;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
/**
* A {@link ConnectionDecorator} that creates logging connections and
* {@link ReportingSQLException}s.
*
* @author Marc Prud'hommeaux
*/
public class LoggingConnectionDecorator implements ConnectionDecorator {
private static final String SEP = J2DoPrivHelper.getLineSeparator();
private static final int WARN_IGNORE = 0;
private static final int WARN_LOG_TRACE = 1;
private static final int WARN_LOG_INFO = 2;
private static final int WARN_LOG_WARN = 3;
private static final int WARN_LOG_ERROR = 4;
private static final int WARN_THROW = 5;
private static final int WARN_HANDLE = 6;
private static final String[] WARNING_ACTIONS = new String[7];
static {
WARNING_ACTIONS[WARN_IGNORE] = "ignore";
WARNING_ACTIONS[WARN_LOG_TRACE] = "trace";
WARNING_ACTIONS[WARN_LOG_INFO] = "info";
WARNING_ACTIONS[WARN_LOG_WARN] = "warn";
WARNING_ACTIONS[WARN_LOG_ERROR] = "error";
WARNING_ACTIONS[WARN_THROW] = "throw";
WARNING_ACTIONS[WARN_HANDLE] = "handle";
}
private final DataSourceLogs _logs = new DataSourceLogs();
private SQLFormatter _formatter;
private boolean _prettyPrint;
private int _prettyPrintLineLength = 60;
private int _warningAction = WARN_IGNORE;
private SQLWarningHandler _warningHandler;
private boolean _printParameters = false;
/**
* If set to <code>true</code>, pretty-print SQL by running it
* through {@link SQLFormatter#prettyPrint}. If
* <code>false</code>, don't pretty-print, and output SQL logs in
* a single line. Pretty-printed SQL can be easier for a human to
* read, but is harder to parse with tools like grep.
*/
public void setPrettyPrint(boolean prettyPrint) {
_prettyPrint = prettyPrint;
if (_formatter == null && _prettyPrint) {
_formatter = new SQLFormatter();
_formatter.setLineLength(_prettyPrintLineLength);
} else if (!_prettyPrint)
_formatter = null;
}
/**
* @see #setPrettyPrint
*/
public boolean getPrettyPrint() {
return _prettyPrint;
}
/**
* The number of characters to print per line when
* pretty-printing of SQL is enabled. Defaults to 60 to provide
* some space for any ant-related characters on the left of a
* standard 80-character display.
*/
public void setPrettyPrintLineLength(int length) {
_prettyPrintLineLength = length;
if (_formatter != null)
_formatter.setLineLength(length);
}
/**
* @see #setPrettyPrintLineLength
*/
public int getPrettyPrintLineLength() {
return _prettyPrintLineLength;
}
/**
* <p>
* Whether parameter values will be printed in exception messages or in trace. This is different from
* trackParameters which controls whether OpenJPA will track parameters internally (visible while debugging and used
* in batching).
* </p>
*/
public boolean getPrintParameters() {
return _printParameters;
}
public void setPrintParameters(boolean printParameters) {
_printParameters = printParameters;
}
/**
* What to do with SQL warnings.
*/
public void setWarningAction(String warningAction) {
int index = Arrays.asList(WARNING_ACTIONS).indexOf(warningAction);
if (index < 0)
index = WARN_IGNORE;
_warningAction = index;
}
/**
* What to do with SQL warnings.
*/
public String getWarningAction() {
return WARNING_ACTIONS[_warningAction];
}
/**
* What to do with SQL warnings.
*/
public void setWarningHandler(SQLWarningHandler warningHandler) {
_warningHandler = warningHandler;
}
/**
* What to do with SQL warnings.
*/
public SQLWarningHandler getWarningHandler() {
return _warningHandler;
}
/**
* The log to write to.
*/
public DataSourceLogs getLogs() {
return _logs;
}
@Override
public Connection decorate(Connection conn) throws SQLException {
return newLoggingConnection(conn);
}
private LoggingConnection newLoggingConnection(Connection conn)
throws SQLException {
return new LoggingConnection(conn);
}
private SQLException wrap(SQLException sqle, Statement stmnt) {
return wrap(sqle, stmnt, null, -1);
}
private SQLException wrap(SQLException sqle, String sql) {
return wrap(sqle, null, sql, -1);
}
private SQLException wrap(SQLException sqle, Statement stmnt, String sql) {
return wrap(sqle, stmnt, sql, -1);
}
private SQLException wrap(SQLException sqle, Statement stmnt, int indexOfFailedBatchObject) {
return wrap(sqle, stmnt, null, indexOfFailedBatchObject);
}
/**
* Include SQL in exception.
*/
private SQLException wrap(SQLException sqle, Statement stmnt, String sql, int indexOfFailedBatchObject) {
ReportingSQLException toReturn = null;
if (sqle instanceof ReportingSQLException) {
toReturn = (ReportingSQLException) sqle;
} else {
toReturn = new ReportingSQLException(sqle, stmnt, sql);
}
toReturn.setIndexOfFirstFailedObject(indexOfFailedBatchObject);
return toReturn;
}
/**
* Interface that allows customization of what to do when
* {@link SQLWarning}s occur.
*/
public interface SQLWarningHandler {
void handleWarning(SQLWarning warning) throws SQLException;
}
/**
* Logging connection.
*/
protected class LoggingConnection extends DelegatingConnection {
public LoggingConnection(Connection conn) throws SQLException {
super(conn);
}
@Override
protected PreparedStatement prepareStatement(String sql, boolean wrap)
throws SQLException {
SQLException err = null;
try {
PreparedStatement stmnt = super.prepareStatement(sql, false);
return newLoggingPreparedStatement(stmnt, sql);
} catch (SQLException se) {
err = wrap(se, sql);
throw err;
} finally {
handleSQLErrors(err);
}
}
@Override
protected PreparedStatement prepareStatement(String sql, int rsType,
int rsConcur, boolean wrap) throws SQLException {
SQLException err = null;
try {
PreparedStatement stmnt = super.prepareStatement
(sql, rsType, rsConcur, false);
return newLoggingPreparedStatement(stmnt, sql);
} catch (SQLException se) {
err = wrap(se, sql);
throw err;
} finally {
handleSQLErrors(err);
}
}
@Override
protected Statement createStatement(boolean wrap) throws SQLException {
SQLException err = null;
try {
Statement stmnt = super.createStatement(false);
return newLoggingStatement(stmnt);
}catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(err);
}
}
@Override
protected Statement createStatement(int type, int concurrency,
boolean wrap) throws SQLException {
SQLException err = null;
try {
Statement stmnt = super.createStatement(type, concurrency,
false);
return newLoggingStatement(stmnt);
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(err);
}
}
@Override
protected CallableStatement prepareCall(String sql, boolean wrap)
throws SQLException {
SQLException err = null;
try {
CallableStatement stmt = super.prepareCall(sql, wrap);
return newLoggingCallableStatement(stmt, sql);
} catch (SQLException se) {
err = wrap(se, sql);
throw err;
} finally {
handleSQLErrors(err);
}
}
private LoggingPreparedStatement newLoggingPreparedStatement
(PreparedStatement stmnt, String sql) throws SQLException {
return new LoggingPreparedStatement(stmnt, sql);
}
private CallableStatement newLoggingCallableStatement(
CallableStatement stmnt, String sql) throws SQLException {
return new LoggingCallableStatement(stmnt, sql);
}
private LoggingStatement newLoggingStatement(Statement stmnt)
throws SQLException {
return new LoggingStatement(stmnt);
}
private LoggingDatabaseMetaData newLoggingDatabaseMetaData
(DatabaseMetaData meta) throws SQLException {
return new LoggingDatabaseMetaData(meta);
}
@Override
public void commit() throws SQLException {
long start = System.currentTimeMillis();
SQLException err = null;
try {
super.commit();
} catch (SQLException se) {
err = se;
throw se;
} finally {
if (_logs.isJDBCEnabled())
_logs.logJDBC("commit", start, this);
handleSQLErrors(err);
}
}
@Override
public void rollback() throws SQLException {
long start = System.currentTimeMillis();
SQLException err = null;
try {
super.rollback();
} catch (SQLException se) {
err = se;
throw se;
} finally {
if (_logs.isJDBCEnabled())
_logs.logJDBC("rollback", start, this);
handleSQLErrors(err);
}
}
@Override
public void close() throws SQLException {
long start = System.currentTimeMillis();
try {
super.close();
} finally {
if (_logs.isJDBCEnabled())
_logs.logJDBC("close", start, this);
}
}
@Override
public Savepoint setSavepoint() throws SQLException {
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.setSavepoint();
} catch (SQLException se) {
err = se;
throw se;
} finally {
if (_logs.isJDBCEnabled())
_logs.logJDBC("savepoint", start, this);
handleSQLErrors(err);
}
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.setSavepoint(name);
} catch (SQLException se) {
err = se;
throw se;
} finally {
if (_logs.isJDBCEnabled())
_logs.logJDBC("savepoint: " + name, start, this);
handleSQLErrors(err);
}
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
long start = System.currentTimeMillis();
SQLException err = null;
try {
super.rollback(savepoint);
} catch (SQLException se) {
err = se;
throw se;
} finally {
if (_logs.isJDBCEnabled()) {
String name = null;
try {
name = savepoint.getSavepointName();
} catch (SQLException sqe) {
name = String.valueOf(savepoint.getSavepointId());
}
_logs.logJDBC("rollback: " + name, start, this);
}
handleSQLErrors(err);
}
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
long start = System.currentTimeMillis();
SQLException err = null;
try {
super.releaseSavepoint(savepoint);
} catch (SQLException se) {
err = se;
throw se;
} finally {
if (_logs.isJDBCEnabled()) {
String name = null;
try {
name = savepoint.getSavepointName();
} catch (SQLException sqe) {
name = String.valueOf(savepoint.getSavepointId());
}
_logs.logJDBC("release: " + name, start, this);
}
handleSQLErrors(err);
}
}
@Override
protected Statement createStatement(int resultSetType,
int resultSetConcurrency, int resultSetHoldability, boolean wrap)
throws SQLException {
SQLException err = null;
try {
Statement stmnt = super.createStatement(resultSetType,
resultSetConcurrency, resultSetHoldability, false);
return newLoggingStatement(stmnt);
}catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(err);
}
}
@Override
protected PreparedStatement prepareStatement(String sql,
int resultSetType, int resultSetConcurrency,
int resultSetHoldability, boolean wrap) throws SQLException {
SQLException err = null;
try {
PreparedStatement stmnt = super.prepareStatement
(sql, resultSetType, resultSetConcurrency,
resultSetHoldability, false);
return newLoggingPreparedStatement(stmnt, sql);
} catch (SQLException se) {
err = wrap(se, sql);
throw err;
} finally {
handleSQLErrors(err);
}
}
@Override
protected PreparedStatement prepareStatement(String sql,
int autoGeneratedKeys, boolean wrap) throws SQLException {
SQLException err = null;
try {
PreparedStatement stmnt = super.prepareStatement
(sql, autoGeneratedKeys, false);
return newLoggingPreparedStatement(stmnt, sql);
} catch (SQLException se) {
err = wrap(se, sql);
throw err;
} finally {
handleSQLErrors(err);
}
}
@Override
protected PreparedStatement prepareStatement(String sql,
int[] columnIndexes, boolean wrap) throws SQLException {
SQLException err = null;
try {
PreparedStatement stmnt = super.prepareStatement
(sql, columnIndexes, false);
return newLoggingPreparedStatement(stmnt, sql);
} catch (SQLException se) {
err = wrap(se, sql);
throw err;
} finally {
handleSQLErrors(err);
}
}
@Override
protected PreparedStatement prepareStatement(String sql,
String[] columnNames, boolean wrap) throws SQLException {
SQLException err = null;
try {
PreparedStatement stmnt = super.prepareStatement
(sql, columnNames, false);
return newLoggingPreparedStatement(stmnt, sql);
} catch (SQLException se) {
err = wrap(se, sql);
throw err;
} finally {
handleSQLErrors(err);
}
}
@Override
protected DatabaseMetaData getMetaData(boolean wrap)
throws SQLException {
return newLoggingDatabaseMetaData(super.getMetaData(false));
}
/**
* Log time elapsed since given start.
*/
private void logTime(long startTime) throws SQLException {
if (_logs.isSQLEnabled())
_logs.logSQL("spent", startTime, this);
}
/**
* Log time elapsed since given start.
*/
private void logSQL(Statement stmnt) throws SQLException {
if (_logs.isSQLEnabled())
_logs.logSQL("executing " + stmnt, this);
}
/**
* Log time elapsed since given start.
*/
private void logBatchSQL(Statement stmnt) throws SQLException {
if (_logs.isSQLEnabled())
_logs.logSQL("executing batch " + stmnt, this);
}
/**
* Handle any {@link SQLWarning}s on the current {@link Connection}.
* Chain throwed SQLWarnings to SQLException.
* @see #handleSQLWarning(SQLWarning)
*/
private void handleSQLErrors(SQLException err) throws SQLException {
if (_warningAction == WARN_IGNORE)
return;
try {
handleSQLWarning(getWarnings());
} catch (SQLException warning) {
if (err != null)
err.setNextException(warning);
else
throw warning;
} finally {
clearWarnings();
}
}
/**
* Handle any {@link SQLWarning}s on the specified {@link Statement}.
* Chain throwed SQLWarnings to SQLException.
*
* @see #handleSQLWarning(SQLWarning)
*/
private void handleSQLErrors(Statement stmnt, SQLException err)
throws SQLException {
if (_warningAction == WARN_IGNORE)
return;
try {
handleSQLWarning(stmnt.getWarnings());
} catch (SQLException warning) {
if (err != null)
err.setNextException(warning);
else
throw warning;
} finally {
stmnt.clearWarnings();
}
}
/**
* Handle any {@link SQLWarning}s on the specified {@link ResultSet}.
* Chain throwed SQLWarnings to SQLException.
*
* @see #handleSQLWarning(SQLWarning)
*/
private void handleSQLErrors(ResultSet rs, SQLException err)
throws SQLException {
if (_warningAction == WARN_IGNORE)
return;
try {
handleSQLWarning(rs.getWarnings());
} catch (SQLException warning){
if (err != null)
err.setNextException(warning);
else
throw warning;
} finally {
rs.clearWarnings();
}
}
/**
* Handle the specified {@link SQLWarning} depending on the
* setting of the {@link #setWarningAction} attribute.
*
* @param warning the warning to handle
*/
private void handleSQLWarning(SQLWarning warning) throws SQLException {
if (warning == null)
return;
if (_warningAction == WARN_IGNORE)
return;
Log log = _logs.getJDBCLog();
for (; warning != null; warning = warning.getNextWarning()) {
switch (_warningAction) {
case WARN_LOG_TRACE:
if (log.isTraceEnabled())
log.trace(warning);
break;
case WARN_LOG_INFO:
if (log.isInfoEnabled())
log.info(warning);
break;
case WARN_LOG_WARN:
if (log.isWarnEnabled())
log.warn(warning);
break;
case WARN_LOG_ERROR:
if (log.isErrorEnabled())
log.error(warning);
break;
case WARN_THROW:
// just throw it as if it were a SQLException
throw warning;
case WARN_HANDLE:
if (_warningHandler != null)
_warningHandler.handleWarning(warning);
break;
default:
// ignore
break;
}
}
}
/**
* Metadata wrapper that logs actions.
*/
protected class LoggingDatabaseMetaData
extends DelegatingDatabaseMetaData {
public LoggingDatabaseMetaData(DatabaseMetaData meta) {
super(meta, LoggingConnection.this);
}
@Override
public ResultSet getBestRowIdentifier(String catalog,
String schema, String table, int scope, boolean nullable)
throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getBestRowIdentifier: "
+ catalog + ", " + schema + ", " + table,
LoggingConnection.this);
return super.getBestRowIdentifier(catalog, schema,
table, scope, nullable);
}
@Override
public ResultSet getCatalogs() throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getCatalogs", LoggingConnection.this);
return super.getCatalogs();
}
@Override
public ResultSet getColumnPrivileges(String catalog, String schema,
String table, String columnNamePattern) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getColumnPrivileges: "
+ catalog + ", " + schema + ", " + table,
LoggingConnection.this);
return super.getColumnPrivileges(catalog, schema,
table, columnNamePattern);
}
@Override
public ResultSet getColumns(String catalog, String schemaPattern,
String tableNamePattern, String columnNamePattern)
throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getColumns: "
+ catalog + ", " + schemaPattern + ", "
+ tableNamePattern + ", " + columnNamePattern,
LoggingConnection.this);
return super.getColumns(catalog, schemaPattern,
tableNamePattern, columnNamePattern);
}
@Override
public ResultSet getCrossReference(String primaryCatalog,
String primarySchema, String primaryTable,
String foreignCatalog, String foreignSchema,
String foreignTable) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getCrossReference: "
+ primaryCatalog + ", " + primarySchema + ", "
+ primaryTable + ", " + foreignCatalog + ", "
+ foreignSchema + ", " + foreignSchema,
LoggingConnection.this);
return super.getCrossReference(primaryCatalog, primarySchema,
primaryTable, foreignCatalog, foreignSchema, foreignTable);
}
@Override
public ResultSet getExportedKeys(String catalog, String schema,
String table) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getExportedKeys: "
+ catalog + ", " + schema + ", " + table,
LoggingConnection.this);
return super.getExportedKeys(catalog, schema, table);
}
@Override
public ResultSet getImportedKeys(String catalog, String schema,
String table) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getImportedKeys: "
+ catalog + ", " + schema + ", " + table,
LoggingConnection.this);
return super.getImportedKeys(catalog, schema, table);
}
@Override
public ResultSet getIndexInfo(String catalog, String schema,
String table, boolean unique, boolean approximate)
throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getIndexInfo: "
+ catalog + ", " + schema + ", " + table,
LoggingConnection.this);
return super.getIndexInfo(catalog, schema, table, unique,
approximate);
}
@Override
public ResultSet getPrimaryKeys(String catalog, String schema,
String table) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getPrimaryKeys: "
+ catalog + ", " + schema + ", " + table,
LoggingConnection.this);
return super.getPrimaryKeys(catalog, schema, table);
}
@Override
public ResultSet getProcedureColumns(String catalog,
String schemaPattern, String procedureNamePattern,
String columnNamePattern) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getProcedureColumns: "
+ catalog + ", " + schemaPattern + ", "
+ procedureNamePattern + ", " + columnNamePattern,
LoggingConnection.this);
return super.getProcedureColumns(catalog, schemaPattern,
procedureNamePattern, columnNamePattern);
}
@Override
public ResultSet getProcedures(String catalog,
String schemaPattern, String procedureNamePattern)
throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getProcedures: "
+ catalog + ", " + schemaPattern + ", "
+ procedureNamePattern, LoggingConnection.this);
return super.getProcedures(catalog, schemaPattern,
procedureNamePattern);
}
@Override
public ResultSet getSchemas() throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getSchemas", LoggingConnection.this);
return super.getSchemas();
}
@Override
public ResultSet getTablePrivileges(String catalog,
String schemaPattern, String tableNamePattern)
throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getTablePrivileges", LoggingConnection.this);
return super.getTablePrivileges(catalog, schemaPattern,
tableNamePattern);
}
@Override
public ResultSet getTables(String catalog, String schemaPattern,
String tableNamePattern, String[] types) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getTables: "
+ catalog + ", " + schemaPattern + ", "
+ tableNamePattern, LoggingConnection.this);
return super.getTables(catalog, schemaPattern,
tableNamePattern, types);
}
@Override
public ResultSet getTableTypes() throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getTableTypes", LoggingConnection.this);
return super.getTableTypes();
}
@Override
public ResultSet getTypeInfo() throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getTypeInfo", LoggingConnection.this);
return super.getTypeInfo();
}
@Override
public ResultSet getUDTs(String catalog, String schemaPattern,
String typeNamePattern, int[] types) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getUDTs", LoggingConnection.this);
return super.getUDTs(catalog, schemaPattern,
typeNamePattern, types);
}
@Override
public ResultSet getVersionColumns(String catalog,
String schema, String table) throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("getVersionColumns: "
+ catalog + ", " + schema + ", " + table,
LoggingConnection.this);
return super.getVersionColumns(catalog, schema, table);
}
}
/**
* Statement wrapper that logs SQL to the parent data source and
* remembers the last piece of SQL to be executed on it.
*/
protected class LoggingStatement extends DelegatingStatement {
private String _sql = null;
public LoggingStatement(Statement stmnt) throws SQLException {
super(stmnt, LoggingConnection.this);
}
private LoggingResultSet newLoggingResultSet(ResultSet rs, Statement stmnt) {
return new LoggingResultSet(rs, stmnt);
}
@Override
public void appendInfo(StringBuffer buf) {
if (_sql != null) {
buf.append(" ");
if (_formatter != null) {
buf.append(SEP);
buf.append(_formatter.prettyPrint(_sql));
} else {
buf.append(_sql);
}
}
}
@Override
protected ResultSet wrapResult(ResultSet rs, boolean wrap) {
if (!wrap || rs == null)
return super.wrapResult(rs, wrap);
return newLoggingResultSet(rs, this);
}
@Override
public void cancel() throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("cancel " + this, LoggingConnection.this);
super.cancel();
}
@Override
protected ResultSet executeQuery(String sql, boolean wrap)
throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeQuery(sql, wrap);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public int executeUpdate(String sql) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(sql);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public boolean execute(String sql) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(sql);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public int executeUpdate(String sql, int i) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(sql, i);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public int executeUpdate(String sql, int[] ia) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(sql, ia);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public int executeUpdate(String sql, String[] sa) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(sql, sa);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public boolean execute(String sql, int i) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(sql, i);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public boolean execute(String sql, int[] ia) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(sql, ia);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
@Override
public boolean execute(String sql, String[] sa) throws SQLException {
_sql = sql;
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(sql, sa);
} catch (SQLException se) {
err = wrap(se, LoggingStatement.this, sql);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingStatement.this, err);
}
}
}
protected class LoggingPreparedStatement
extends DelegatingPreparedStatement {
private final String _sql;
private List<String> _params = null;
private List<List<String>> _paramBatch = null;
// When batching is used, this variable contains the index into the
// last successfully executed batched statement.
int batchedRowsBaseIndex = 0;
public LoggingPreparedStatement(PreparedStatement stmnt, String sql)
throws SQLException {
super(stmnt, LoggingConnection.this);
_sql = sql;
}
private LoggingResultSet newLoggingResultSet(ResultSet rs,
PreparedStatement stmnt) {
return new LoggingResultSet(rs, stmnt);
}
@Override
protected ResultSet wrapResult(ResultSet rs, boolean wrap) {
if (!wrap || rs == null)
return super.wrapResult(rs, wrap);
return newLoggingResultSet(rs, this);
}
@Override
protected ResultSet executeQuery(String sql, boolean wrap)
throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeQuery(sql, wrap);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this, sql);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public int executeUpdate(String sql) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(sql);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this, sql);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public boolean execute(String sql) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(sql);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this, sql);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
protected ResultSet executeQuery(boolean wrap) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeQuery(wrap);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this, _sql);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public int executeUpdate() throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate();
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public int[] executeBatch() throws SQLException {
int indexOfFirstFailedObject = -1;
logBatchSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
int[] toReturn = super.executeBatch();
//executeBatch is called any time the number of batched statements
//is equal to, or less than, batchLimit. In the 'catch' block below,
//the logic seeks to find an index based on the current executeBatch
//results. This is fine when executeBatch is only called once, but
//if executeBatch is called many times, the _paramsBatch will continue
//to grow, as such, to index into _paramsBatch, we need to take into
//account the number of times executeBatch is called in or der to
//correctly index into _paramsBatch. To that end, each time executeBatch
//is called, lets get the size of _paramBatch. This will effectively
//tell us the index of the last successfully executed batch statement.
//If an exception is caused, then we know that _paramBatch.size was
//the index of the LAST row to successfully execute.
if (_paramBatch != null){
batchedRowsBaseIndex = _paramBatch.size();
}
return toReturn;
} catch (SQLException se) {
// if the exception is a BatchUpdateException, and
// we are tracking parameters, then set the current
// parameter set to be the index of the failed
// statement so that the ReportingSQLException will
// show the correct param(s)
if (se instanceof BatchUpdateException
&& _paramBatch != null && shouldTrackParameters()) {
int[] count = ((BatchUpdateException) se).
getUpdateCounts();
if (count != null && count.length <= _paramBatch.size())
{
for (int i = 0; i < count.length; i++) {
// -3 is Statement.STATEMENT_FAILED, but is
// only available in JDK 1.4+
if (count[i] == Statement.EXECUTE_FAILED) {
indexOfFirstFailedObject = i;
break;
}
}
// no -3 element: it may be that the server stopped
// processing, so the size of the count will be
// the index
//See the Javadoc for 'getUpdateCounts'; a provider
//may stop processing when the first failure occurs,
//as such, it may only return 'UpdateCounts' for the
//first few which pass. As such, the failed
//index is 'count.length', NOT count.length+1. That
//is, if the provider ONLY returns the first few that
//passes (i.e. say an array of [1,1] is returned) then
//length is 2, and since _paramBatch starts at 0, we
//don't want to use length+1 as that will give us the
//wrong index.
if (indexOfFirstFailedObject == -1){
indexOfFirstFailedObject = count.length;
}
//Finally, whatever the index is at this point, add batchedRowsBaseIndex
//to it to get the final index. Recall, we need to start our index from the
//last batch which successfully executed.
indexOfFirstFailedObject += batchedRowsBaseIndex;
// set the current params to the saved values
if (indexOfFirstFailedObject < _paramBatch.size())
_params = (List<String>) _paramBatch.get(indexOfFirstFailedObject);
}
}
err = wrap(se, LoggingPreparedStatement.this, indexOfFirstFailedObject);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public boolean execute() throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute();
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public int executeUpdate(String s, int i) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(s, i);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public int executeUpdate(String s, int[] ia) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(s, ia);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public int executeUpdate(String s, String[] sa) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(s, sa);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public boolean execute(String s, int i) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(s, i);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public boolean execute(String s, int[] ia) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(s, ia);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public boolean execute(String s, String[] sa) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(s, sa);
} catch (SQLException se) {
err = wrap(se, LoggingPreparedStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingPreparedStatement.this, err);
}
}
@Override
public void cancel() throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("cancel " + this + ": " + _sql,
LoggingConnection.this);
super.cancel();
}
@Override
public void setNull(int i1, int i2) throws SQLException {
setLogParameter(i1, "null", null);
super.setNull(i1, i2);
}
@Override
public void setBoolean(int i, boolean b) throws SQLException {
setLogParameter(i, b);
super.setBoolean(i, b);
}
@Override
public void setByte(int i, byte b) throws SQLException {
setLogParameter(i, b);
super.setByte(i, b);
}
@Override
public void setShort(int i, short s) throws SQLException {
setLogParameter(i, s);
super.setShort(i, s);
}
@Override
public void setInt(int i1, int i2) throws SQLException {
setLogParameter(i1, i2);
super.setInt(i1, i2);
}
@Override
public void setLong(int i, long l) throws SQLException {
setLogParameter(i, l);
super.setLong(i, l);
}
@Override
public void setFloat(int i, float f) throws SQLException {
setLogParameter(i, f);
super.setFloat(i, f);
}
@Override
public void setDouble(int i, double d) throws SQLException {
setLogParameter(i, d);
super.setDouble(i, d);
}
@Override
public void setBigDecimal(int i, BigDecimal bd)
throws SQLException {
setLogParameter(i, "BigDecimal", bd);
super.setBigDecimal(i, bd);
}
@Override
public void setString(int i, String s) throws SQLException {
setLogParameter(i, "String", s);
super.setString(i, s);
}
@Override
public void setBytes(int i, byte[] b) throws SQLException {
setLogParameter(i, "byte[]", b);
super.setBytes(i, b);
}
@Override
public void setDate(int i, Date d) throws SQLException {
setLogParameter(i, "Date", d);
super.setDate(i, d);
}
@Override
public void setTime(int i, Time t) throws SQLException {
setLogParameter(i, "Time", t);
super.setTime(i, t);
}
@Override
public void setTimestamp(int i, Timestamp t) throws SQLException {
setLogParameter(i, "Timestamp", t);
super.setTimestamp(i, t);
}
@Override
public void setAsciiStream(int i1, InputStream is, int i2)
throws SQLException {
setLogParameter(i1, "InputStream", is);
super.setAsciiStream(i1, is, i2);
}
@Override
@Deprecated
public void setUnicodeStream(int i1, InputStream is, int i2)
throws SQLException {
setLogParameter(i1, "InputStream", is);
super.setUnicodeStream(i2, is, i2);
}
@Override
public void setBinaryStream(int i1, InputStream is, int i2)
throws SQLException {
setLogParameter(i1, "InputStream", is);
super.setBinaryStream(i1, is, i2);
}
@Override
public void setBinaryStream(int i1, InputStream is)
throws SQLException {
setLogParameter(i1, "InputStream", is);
super.setBinaryStream(i1, is);
}
@Override
public void clearParameters() throws SQLException {
clearLogParameters(false);
super.clearParameters();
}
@Override
public void setObject(int i1, Object o, int i2, int i3)
throws SQLException {
setLogParameter(i1, "Object", o);
super.setObject(i1, o, i2, i3);
}
@Override
public void setObject(int i1, Object o, int i2)
throws SQLException {
setLogParameter(i1, "Object", o);
super.setObject(i1, o, i2);
}
@Override
public void setObject(int i, Object o) throws SQLException {
setLogParameter(i, "Object", o);
super.setObject(i, o);
}
@Override
public void addBatch() throws SQLException {
if (_logs.isSQLEnabled())
_logs.logSQL("batching " + this, LoggingConnection.this);
long start = System.currentTimeMillis();
try {
super.addBatch();
if (shouldTrackParameters()) {
// make sure our list is initialized
if (_paramBatch == null)
_paramBatch = new ArrayList<>();
// copy parameters since they will be re-used
if (_params != null) {
List<String> copyParms =
new ArrayList<>(_params);
_paramBatch.add(copyParms);
}
else
_paramBatch.add(null);
}
}
finally {
logTime(start);
}
}
@Override
public void setCharacterStream(int i1, Reader r, int i2)
throws SQLException {
setLogParameter(i1, "Reader", r);
super.setCharacterStream(i1, r, i2);
}
@Override
public void setRef(int i, Ref r) throws SQLException {
setLogParameter(i, "Ref", r);
super.setRef(i, r);
}
@Override
public void setBlob(int i, Blob b) throws SQLException {
setLogParameter(i, "Blob", b);
super.setBlob(i, b);
}
@Override
public void setClob(int i, Clob c) throws SQLException {
setLogParameter(i, "Clob", c);
super.setClob(i, c);
}
@Override
public void setArray(int i, Array a) throws SQLException {
setLogParameter(i, "Array", a);
super.setArray(i, a);
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return super.getMetaData();
}
@Override
public void setDate(int i, Date d, Calendar c) throws SQLException {
setLogParameter(i, "Date", d);
super.setDate(i, d, c);
}
@Override
public void setTime(int i, Time t, Calendar c) throws SQLException {
setLogParameter(i, "Time", t);
super.setTime(i, t, c);
}
@Override
public void setTimestamp(int i, Timestamp t, Calendar c)
throws SQLException {
setLogParameter(i, "Timestamp", t);
super.setTimestamp(i, t, c);
}
@Override
public void setNull(int i1, int i2, String s) throws SQLException {
setLogParameter(i1, "null", null);
super.setNull(i1, i2, s);
}
@Override
public void setURL(int i, URL u) throws SQLException {
setLogParameter(i, "URL", u);
super.setURL(i, u);
}
@Override
protected void appendInfo(StringBuffer buf) {
buf.append(" ");
if (_formatter != null) {
buf.append(SEP);
buf.append(_formatter.prettyPrint(_sql));
buf.append(SEP);
} else {
buf.append(_sql);
}
StringBuilder paramBuf = null;
if (_params != null && !_params.isEmpty()) {
paramBuf = new StringBuilder();
for (Iterator<String> itr = _params.iterator(); itr
.hasNext();) {
if (_printParameters) {
paramBuf.append(itr.next());
} else {
paramBuf.append("?");
itr.next();
}
if (itr.hasNext()) {
paramBuf.append(", ");
}
}
}
if (paramBuf != null) {
if (!_prettyPrint) {
buf.append(" ");
}
buf.append("[params=").append(paramBuf.toString()).append("]");
}
super.appendInfo(buf);
}
private void clearLogParameters(boolean batch) {
if (_params != null) {
_params.clear();
}
if (batch && _paramBatch != null) {
_paramBatch.clear();
}
}
private boolean shouldTrackParameters() {
return _printParameters || _logs.isSQLEnabled();
}
private void setLogParameter(int index, boolean val) {
if (shouldTrackParameters())
setLogParameter(index, "(boolean) " + val);
}
private void setLogParameter(int index, byte val) {
if (shouldTrackParameters())
setLogParameter(index, "(byte) " + val);
}
private void setLogParameter(int index, double val) {
if (shouldTrackParameters())
setLogParameter(index, "(double) " + val);
}
private void setLogParameter(int index, float val) {
if (shouldTrackParameters())
setLogParameter(index, "(float) " + val);
}
private void setLogParameter(int index, int val) {
if (shouldTrackParameters())
setLogParameter(index, "(int) " + val);
}
private void setLogParameter(int index, long val) {
if (shouldTrackParameters())
setLogParameter(index, "(long) " + val);
}
private void setLogParameter(int index, short val) {
if (shouldTrackParameters())
setLogParameter(index, "(short) " + val);
}
private void setLogParameter(int index, String type, Object val) {
if (shouldTrackParameters())
setLogParameter(index, "(" + type + ") " + val);
}
private void setLogParameter(int index, String val) {
if (_params == null)
_params = new ArrayList<>();
while (_params.size() < index)
_params.add(null);
if (val.length() > 80)
val = val.substring(0, 77) + "...";
_params.set(index - 1, val);
}
}
/**
* Warning-handling result set.
*/
protected class LoggingResultSet extends DelegatingResultSet {
public LoggingResultSet(ResultSet rs, Statement stmnt) {
super(rs, stmnt);
}
@Override
public boolean next() throws SQLException {
SQLException err = null;
try {
return super.next();
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public void close() throws SQLException {
SQLException err = null;
try {
super.close();
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public void beforeFirst() throws SQLException {
SQLException err = null;
try {
super.beforeFirst();
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public void afterLast() throws SQLException {
SQLException err = null;
try {
super.afterLast();
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public boolean first() throws SQLException {
SQLException err = null;
try {
return super.first();
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public boolean last() throws SQLException {
SQLException err = null;
try {
return super.last();
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public boolean absolute(int a) throws SQLException {
SQLException err = null;
try {
return super.absolute(a);
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public boolean relative(int a) throws SQLException {
SQLException err = null;
try {
return super.relative(a);
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
@Override
public boolean previous() throws SQLException {
SQLException err = null;
try {
return super.previous();
} catch (SQLException se) {
err = se;
throw se;
} finally {
handleSQLErrors(LoggingResultSet.this, err);
}
}
}
/**
* CallableStatement decorated with logging.
* Similar to {@link LoggingPreparedStatement} but can not be extended
* due to the existing delegation hierarchy.
*/
protected class LoggingCallableStatement extends
DelegatingCallableStatement {
private final String _sql;
private List<String> _params = null;
private List<List<String>> _paramBatch = null;
//When batching is used, this variable contains the index into the last
//successfully executed batched statement.
int batchedRowsBaseIndex = 0;
public LoggingCallableStatement(CallableStatement stmt, String sql)
throws SQLException {
super(stmt, LoggingConnection.this);
_sql = sql;
}
private LoggingResultSet newLoggingResultSet(ResultSet rs,
CallableStatement stmnt) {
return new LoggingResultSet(rs, stmnt);
}
protected ResultSet wrapResult(ResultSet rs, boolean wrap) {
if (!wrap || rs == null)
return super.wrapResult(wrap, rs);
return newLoggingResultSet(rs, this);
}
@Override
protected ResultSet executeQuery(String sql, boolean wrap)
throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeQuery(sql, wrap);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this, sql);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public int executeUpdate(String sql) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(sql);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this, sql);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public boolean execute(String sql) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(sql);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this, sql);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
protected ResultSet executeQuery(boolean wrap) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeQuery(wrap);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public int executeUpdate() throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate();
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public int[] executeBatch() throws SQLException {
int indexOfFirstFailedObject = -1;
logBatchSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
int[] toReturn = super.executeBatch();
//executeBatch is called any time the number of batched statements
//is equal to, or less than, batchLimit. In the 'catch' block below,
//the logic seeks to find an index based on the current executeBatch
//results. This is fine when executeBatch is only called once, but
//if executeBatch is called many times, the _paramsBatch will continue
//to grow, as such, to index into _paramsBatch, we need to take into
//account the number of times executeBatch is called in order to
//correctly index into _paramsBatch. To that end, each time executeBatch
//is called, lets get the size of _paramBatch. This will effectively
//tell us the index of the last successfully executed batch statement.
//If an exception is caused, then we know that _paramBatch.size was
//the index of the LAST row to successfully execute.
if (_paramBatch != null){
batchedRowsBaseIndex = _paramBatch.size();
}
return toReturn;
} catch (SQLException se) {
// if the exception is a BatchUpdateException, and
// we are tracking parameters, then set the current
// parameter set to be the index of the failed
// statement so that the ReportingSQLException will
// show the correct param
if (se instanceof BatchUpdateException
&& _paramBatch != null && shouldTrackParameters()) {
int[] count = ((BatchUpdateException) se).
getUpdateCounts();
if (count != null && count.length <= _paramBatch.size())
{
for (int i = 0; i < count.length; i++) {
// -3 is Statement.STATEMENT_FAILED, but is
// only available in JDK 1.4+
if (count[i] == Statement.EXECUTE_FAILED) {
indexOfFirstFailedObject = i;
break;
}
}
// no -3 element: it may be that the server stopped
// processing, so the size of the count will be
// the index
//See the Javadoc for 'getUpdateCounts'; a provider
//may stop processing when the first failure occurs,
//as such, it may only return 'UpdateCounts' for the
//first few which pass. As such, the failed
//index is 'count.length', NOT count.length+1. That
//is, if the provider ONLY returns the first few that
//passes (i.e. say an array of [1,1] is returned) then
//length is 2, and since _paramBatch starts at 0, we
//don't want to use length+1 as that will give us the
//wrong index.
if (indexOfFirstFailedObject == -1){
indexOfFirstFailedObject = count.length;
}
//Finally, whatever the index is at this point, add batchedRowsBaseIndex
//to it to get the final index. Recall, we need to start our index from the
//last batch which successfully executed.
indexOfFirstFailedObject += batchedRowsBaseIndex;
// set the current params to the saved values
if (indexOfFirstFailedObject < _paramBatch.size()){
_params = (List<String>) _paramBatch.get(indexOfFirstFailedObject);
}
}
}
err = wrap(se, LoggingCallableStatement.this, indexOfFirstFailedObject);
throw err;
} finally {
logTime(start);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public boolean execute() throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute();
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public int executeUpdate(String s, int i) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(s, i);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public int executeUpdate(String s, int[] ia) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(s, ia);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public int executeUpdate(String s, String[] sa) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.executeUpdate(s, sa);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public boolean execute(String s, int i) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(s, i);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public boolean execute(String s, int[] ia) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(s, ia);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public boolean execute(String s, String[] sa) throws SQLException {
logSQL(this);
long start = System.currentTimeMillis();
SQLException err = null;
try {
return super.execute(s, sa);
} catch (SQLException se) {
err = wrap(se, LoggingCallableStatement.this);
throw err;
} finally {
logTime(start);
clearLogParameters(true);
handleSQLErrors(LoggingCallableStatement.this, err);
}
}
@Override
public void cancel() throws SQLException {
if (_logs.isJDBCEnabled())
_logs.logJDBC("cancel " + this + ": " + _sql,
LoggingConnection.this);
super.cancel();
}
@Override
public void setNull(int i1, int i2) throws SQLException {
setLogParameter(i1, "null", null);
super.setNull(i1, i2);
}
@Override
public void setBoolean(int i, boolean b) throws SQLException {
setLogParameter(i, b);
super.setBoolean(i, b);
}
@Override
public void setByte(int i, byte b) throws SQLException {
setLogParameter(i, b);
super.setByte(i, b);
}
@Override
public void setShort(int i, short s) throws SQLException {
setLogParameter(i, s);
super.setShort(i, s);
}
@Override
public void setInt(int i1, int i2) throws SQLException {
setLogParameter(i1, i2);
super.setInt(i1, i2);
}
@Override
public void setLong(int i, long l) throws SQLException {
setLogParameter(i, l);
super.setLong(i, l);
}
@Override
public void setFloat(int i, float f) throws SQLException {
setLogParameter(i, f);
super.setFloat(i, f);
}
@Override
public void setDouble(int i, double d) throws SQLException {
setLogParameter(i, d);
super.setDouble(i, d);
}
@Override
public void setBigDecimal(int i, BigDecimal bd)
throws SQLException {
setLogParameter(i, "BigDecimal", bd);
super.setBigDecimal(i, bd);
}
@Override
public void setString(int i, String s) throws SQLException {
setLogParameter(i, "String", s);
super.setString(i, s);
}
@Override
public void setBytes(int i, byte[] b) throws SQLException {
setLogParameter(i, "byte[]", b);
super.setBytes(i, b);
}
@Override
public void setDate(int i, Date d) throws SQLException {
setLogParameter(i, "Date", d);
super.setDate(i, d);
}
@Override
public void setTime(int i, Time t) throws SQLException {
setLogParameter(i, "Time", t);
super.setTime(i, t);
}
@Override
public void setTimestamp(int i, Timestamp t) throws SQLException {
setLogParameter(i, "Timestamp", t);
super.setTimestamp(i, t);
}
@Override
public void setAsciiStream(int i1, InputStream is, int i2)
throws SQLException {
setLogParameter(i1, "InputStream", is);
super.setAsciiStream(i1, is, i2);
}
@Override
@Deprecated
public void setUnicodeStream(int i1, InputStream is, int i2)
throws SQLException {
setLogParameter(i1, "InputStream", is);
super.setUnicodeStream(i2, is, i2);
}
@Override
public void setBinaryStream(int i1, InputStream is, int i2)
throws SQLException {
setLogParameter(i1, "InputStream", is);
super.setBinaryStream(i1, is, i2);
}
@Override
public void clearParameters() throws SQLException {
clearLogParameters(false);
super.clearParameters();
}
@Override
public void setObject(int i1, Object o, int i2, int i3)
throws SQLException {
setLogParameter(i1, "Object", o);
super.setObject(i1, o, i2, i3);
}
@Override
public void setObject(int i1, Object o, int i2)
throws SQLException {
setLogParameter(i1, "Object", o);
super.setObject(i1, o, i2);
}
@Override
public void setObject(int i, Object o) throws SQLException {
setLogParameter(i, "Object", o);
super.setObject(i, o);
}
@Override
public void addBatch() throws SQLException {
if (_logs.isSQLEnabled())
_logs.logSQL("batching " + this, LoggingConnection.this);
long start = System.currentTimeMillis();
try {
super.addBatch();
if (shouldTrackParameters()) {
// make sure our list is initialized
if (_paramBatch == null)
_paramBatch = new ArrayList<>();
// copy parameters since they will be re-used
if (_params != null) {
List<String> copyParams =
new ArrayList<>(_params);
_paramBatch.add(copyParams);
}
else
_paramBatch.add(null);
}
}
finally {
logTime(start);
}
}
@Override
public void setCharacterStream(int i1, Reader r, int i2)
throws SQLException {
setLogParameter(i1, "Reader", r);
super.setCharacterStream(i1, r, i2);
}
@Override
public void setRef(int i, Ref r) throws SQLException {
setLogParameter(i, "Ref", r);
super.setRef(i, r);
}
@Override
public void setBlob(int i, Blob b) throws SQLException {
setLogParameter(i, "Blob", b);
super.setBlob(i, b);
}
@Override
public void setClob(int i, Clob c) throws SQLException {
setLogParameter(i, "Clob", c);
super.setClob(i, c);
}
@Override
public void setArray(int i, Array a) throws SQLException {
setLogParameter(i, "Array", a);
super.setArray(i, a);
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return super.getMetaData();
}
@Override
public void setDate(int i, Date d, Calendar c) throws SQLException {
setLogParameter(i, "Date", d);
super.setDate(i, d, c);
}
@Override
public void setTime(int i, Time t, Calendar c) throws SQLException {
setLogParameter(i, "Time", t);
super.setTime(i, t, c);
}
@Override
public void setTimestamp(int i, Timestamp t, Calendar c)
throws SQLException {
setLogParameter(i, "Timestamp", t);
super.setTimestamp(i, t, c);
}
@Override
public void setNull(int i1, int i2, String s) throws SQLException {
setLogParameter(i1, "null", null);
super.setNull(i1, i2, s);
}
@Override
public void setURL(int i, URL u) throws SQLException {
setLogParameter(i, "URL", u);
super.setURL(i, u);
}
@Override
protected void appendInfo(StringBuffer buf) {
buf.append(" ");
if (_formatter != null) {
buf.append(SEP);
buf.append(_formatter.prettyPrint(_sql));
buf.append(SEP);
} else {
buf.append(_sql);
}
StringBuilder paramBuf = null;
if (_params != null && !_params.isEmpty()) {
paramBuf = new StringBuilder();
for (Iterator<String> itr = _params.iterator(); itr
.hasNext();) {
paramBuf.append(itr.next());
if (itr.hasNext())
paramBuf.append(", ");
}
}
if (paramBuf != null) {
if (!_prettyPrint)
buf.append(" ");
buf.append("[params=").
append(paramBuf.toString()).append("]");
}
super.appendInfo(buf);
}
protected void clearLogParameters(boolean batch) {
if (_params != null)
_params.clear();
if (batch && _paramBatch != null)
_paramBatch.clear();
}
private boolean shouldTrackParameters() {
return _printParameters || _logs.isSQLEnabled();
}
private void setLogParameter(int index, boolean val) {
if (shouldTrackParameters())
setLogParameter(index, "(boolean) " + val);
}
private void setLogParameter(int index, byte val) {
if (shouldTrackParameters())
setLogParameter(index, "(byte) " + val);
}
private void setLogParameter(int index, double val) {
if (shouldTrackParameters())
setLogParameter(index, "(double) " + val);
}
private void setLogParameter(int index, float val) {
if (shouldTrackParameters())
setLogParameter(index, "(float) " + val);
}
private void setLogParameter(int index, int val) {
if (shouldTrackParameters())
setLogParameter(index, "(int) " + val);
}
private void setLogParameter(int index, long val) {
if (shouldTrackParameters())
setLogParameter(index, "(long) " + val);
}
private void setLogParameter(int index, short val) {
if (shouldTrackParameters())
setLogParameter(index, "(short) " + val);
}
private void setLogParameter(int index, String type, Object val) {
if (shouldTrackParameters())
setLogParameter(index, "(" + type + ") " + val);
}
private void setLogParameter(int index, String val) {
if (_params == null)
_params = new ArrayList<>();
while (_params.size() < index)
_params.add(null);
if (val.length() > 80)
val = val.substring(0, 77) + "...";
_params.set(index - 1, val);
}
}
}
}