content: package net.csdn.hibernate.support.filter;
  
  import com.alibaba.druid.filter.Filter;
  import com.alibaba.druid.filter.FilterChain;
  import com.alibaba.druid.filter.FilterEventAdapter;
  import com.alibaba.druid.filter.stat.StatFilter;
  import com.alibaba.druid.filter.stat.StatFilterContext;
  import com.alibaba.druid.filter.stat.StatFilterMBean;
  import com.alibaba.druid.pool.DruidDataSource;
  import com.alibaba.druid.pool.DruidPooledConnection;
  import com.alibaba.druid.proxy.jdbc.*;
  import com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils;
  import com.alibaba.druid.stat.*;
  import com.alibaba.druid.support.json.JSONWriter;
  import com.alibaba.druid.support.logging.Log;
  import com.alibaba.druid.support.logging.LogFactory;
  import com.alibaba.druid.support.profile.Profiler;
  
  import java.io.InputStream;
  import java.io.Reader;
  import java.sql.*;
  import java.util.Date;
  import java.util.Properties;
  import java.util.concurrent.atomic.AtomicLong;
  
  /**
   * 8/20/13 WilliamZhu(allwefantasy@gmail.com)
   */
  public class CSDNStatFilterstat extends FilterEventAdapter implements StatFilterMBean {
  
      private static ThreadLocal<AtomicLong> SQLTIME = new ThreadLocal<AtomicLong>();
  
      public static void setSQLTIME(AtomicLong value) {
          SQLTIME.set(value);
      }
  
      public static void removeSQLTIME() {
          SQLTIME.remove();
      }
  
      public static AtomicLong SQLTIME() {
          return SQLTIME.get();
      }
  
      private final static Log LOG = LogFactory.getLog(CSDNStatFilterstat.class);
  
      private static final String SYS_PROP_LOG_SLOW_SQL = "druid.stat.logSlowSql";
      private static final String SYS_PROP_SLOW_SQL_MILLIS = "druid.stat.slowSqlMillis";
      private static final String SYS_PROP_MERGE_SQL = "druid.stat.mergeSql";
  
      public final static String ATTR_NAME_CONNECTION_STAT = "stat.conn";
      public final static String ATTR_NAME_STATEMENT_STAT = "stat.stmt";
      public final static String ATTR_UPDATE_COUNT = "stat.updteCount";
      public final static String ATTR_TRANSACTION = "stat.tx";
      public final static String ATTR_RESULTSET_CLOSED = "stat.rs.closed";
  
      // protected JdbcDataSourceStat dataSourceStat;
  
      @Deprecated
      protected final JdbcStatementStat statementStat = JdbcStatManager.getInstance().getStatementStat();
  
      @Deprecated
      protected final JdbcResultSetStat resultSetStat = JdbcStatManager.getInstance().getResultSetStat();
  
      private boolean connectionStackTraceEnable = false;
  
      // 3 seconds is slow sql
      protected long slowSqlMillis = 3 * 1000;
  
      protected boolean logSlowSql = false;
  
      private String dbType;
  
      private boolean mergeSql = false;
  
      public CSDNStatFilterstat() {
      }
  
      public String getDbType() {
          return dbType;
      }
  
      public void setDbType(String dbType) {
          this.dbType = dbType;
      }
  
      public long getSlowSqlMillis() {
          return slowSqlMillis;
      }
  
      public void setSlowSqlMillis(long slowSqlMillis) {
          this.slowSqlMillis = slowSqlMillis;
      }
  
      public boolean isLogSlowSql() {
          return logSlowSql;
      }
  
      public void setLogSlowSql(boolean logSlowSql) {
          this.logSlowSql = logSlowSql;
      }
  
      public boolean isConnectionStackTraceEnable() {
          return connectionStackTraceEnable;
      }
  
      public void setConnectionStackTraceEnable(boolean connectionStackTraceEnable) {
          this.connectionStackTraceEnable = connectionStackTraceEnable;
      }
  
      public boolean isMergeSql() {
          return mergeSql;
      }
  
      public void setMergeSql(boolean mergeSql) {
          this.mergeSql = mergeSql;
      }
  
      @Deprecated
      public String mergeSql(String sql) {
          return this.mergeSql(sql, dbType);
      }
  
      public String mergeSql(String sql, String dbType) {
          if (!mergeSql) {
              return sql;
          }
  
          try {
              sql = ParameterizedOutputVisitorUtils.parameterize(sql, dbType);
          } catch (Exception e) {
              LOG.error("merge sql error, dbType " + dbType + ", sql : \n" + sql, e);
          }
  
          return sql;
      }
  
      @Override
      public synchronized void init(DataSourceProxy dataSource) {
          if (this.dbType == null || this.dbType.trim().length() == 0) {
              this.dbType = dataSource.getDbType();
          }
  
          configFromProperties(dataSource.getConnectProperties());
          configFromProperties(System.getProperties());
      }
  
      public void configFromProperties(Properties properties) {
          if (properties == null) {
              return;
          }
  
          {
              String property = properties.getProperty(SYS_PROP_MERGE_SQL);
              if ("true".equals(property)) {
                  this.mergeSql = true;
              } else if ("false".equals(property)) {
                  this.mergeSql = false;
              }
          }
  
          {
              String property = properties.getProperty(SYS_PROP_SLOW_SQL_MILLIS);
              if (property != null && property.trim().length() > 0) {
                  property = property.trim();
                  try {
                      this.slowSqlMillis = Long.parseLong(property);
                  } catch (Exception e) {
                      LOG.error("property 'druid.stat.slowSqlMillis' format error");
                  }
              }
          }
  
          {
              String property = properties.getProperty(SYS_PROP_LOG_SLOW_SQL);
              if ("true".equals(property)) {
                  this.logSlowSql = true;
              } else if ("false".equals(property)) {
                  this.logSlowSql = false;
              }
          }
      }
  
      public ConnectionProxy connection_connect(FilterChain chain, Properties info) throws SQLException {
          ConnectionProxy connection = null;
          {
              long startNano = System.nanoTime();
              long startTime = System.currentTimeMillis();
  
              long nanoSpan;
              long nowTime = System.currentTimeMillis();
  
              JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
              dataSourceStat.getConnectionStat().beforeConnect();
              try {
                  connection = chain.connection_connect(info);
                  nanoSpan = System.nanoTime() - startNano;
              } catch (SQLException ex) {
                  dataSourceStat.getConnectionStat().connectError(ex);
                  throw ex;
              }
              dataSourceStat.getConnectionStat().afterConnected(nanoSpan);
  
              if (connection != null) {
                  JdbcConnectionStat.Entry statEntry = getConnectionInfo(connection);
  
                  dataSourceStat.getConnections().put(connection.getId(), statEntry);
  
                  statEntry.setConnectTime(new Date(startTime));
                  statEntry.setConnectTimespanNano(nanoSpan);
                  statEntry.setEstablishNano(System.nanoTime());
                  statEntry.setEstablishTime(nowTime);
                  statEntry.setConnectStackTrace(new Exception());
  
                  dataSourceStat.getConnectionStat().setActiveCount(dataSourceStat.getConnections().size());
              }
          }
          return connection;
      }
  
      @Override
      public void connection_close(FilterChain chain, ConnectionProxy connection) throws SQLException {
          if (connection.getCloseCount() == 0) {
              long nowNano = System.nanoTime();
  
              JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
              dataSourceStat.getConnectionStat().incrementConnectionCloseCount();
  
              JdbcConnectionStat.Entry connectionInfo = getConnectionInfo(connection);
  
              long aliveNanoSpan = nowNano - connectionInfo.getEstablishNano();
  
              JdbcConnectionStat.Entry existsConnection = dataSourceStat.getConnections().remove(connection.getId());
              if (existsConnection != null) {
                  dataSourceStat.getConnectionStat().afterClose(aliveNanoSpan);
              }
          }
  
          chain.connection_close(connection);
          // duplicate close, C3P0等连接池，在某些情况下会关闭连接多次。
      }
  
      @Override
      public void connection_commit(FilterChain chain, ConnectionProxy connection) throws SQLException {
          chain.connection_commit(connection);
  
          JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
          dataSourceStat.getConnectionStat().incrementConnectionCommitCount();
      }
  
      @Override
      public void connection_rollback(FilterChain chain, ConnectionProxy connection) throws SQLException {
          chain.connection_rollback(connection);
  
          JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
          dataSourceStat.getConnectionStat().incrementConnectionRollbackCount();
          dataSourceStat.getConnectionStat().incrementConnectionRollbackCount();
      }
  
      @Override
      public void connection_rollback(FilterChain chain, ConnectionProxy connection, Savepoint savepoint)
              throws SQLException {
          chain.connection_rollback(connection, savepoint);
  
          JdbcDataSourceStat dataSourceStat = connection.getDirectDataSource().getDataSourceStat();
          dataSourceStat.getConnectionStat().incrementConnectionRollbackCount();
      }
  
      @Override
      public void statementCreateAfter(StatementProxy statement) {
          JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
          dataSourceStat.getStatementStat().incrementCreateCounter();
  
          super.statementCreateAfter(statement);
      }
  
      @Override
      public void statementPrepareCallAfter(CallableStatementProxy statement) {
          JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
          dataSourceStat.getStatementStat().incrementPrepareCallCount();
  
          JdbcSqlStat sqlStat = createSqlStat(statement, statement.getSql());
          statement.setSqlStat(sqlStat);
      }
  
      @Override
      public void statementPrepareAfter(PreparedStatementProxy statement) {
          JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
          dataSourceStat.getStatementStat().incrementPrepareCounter();
          JdbcSqlStat sqlStat = createSqlStat(statement, statement.getSql());
          statement.setSqlStat(sqlStat);
      }
  
      @Override
      public void statement_close(FilterChain chain, StatementProxy statement) throws SQLException {
          chain.statement_close(statement);
  
          JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
          dataSourceStat.getStatementStat().incrementStatementCloseCounter();
          JdbcStatContext context = JdbcStatManager.getInstance().getStatContext();
          if (context != null) {
              context.setName(null);
              context.setFile(null);
              context.setSql(null);
          }
      }
  
      @Override
      protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) {
          internalBeforeStatementExecute(statement, sql);
      }
  
      @Override
      protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) {
          internalAfterStatementExecute(statement, false, updateCount);
      }
  
      @Override
      protected void statementExecuteQueryBefore(StatementProxy statement, String sql) {
          internalBeforeStatementExecute(statement, sql);
      }
  
      @Override
      protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {
          internalAfterStatementExecute(statement, true);
      }
  
      @Override
      protected void statementExecuteBefore(StatementProxy statement, String sql) {
          internalBeforeStatementExecute(statement, sql);
      }
  
      @Override
      protected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) {
          internalAfterStatementExecute(statement, firstResult);
      }
  
      @Override
      protected void statementExecuteBatchBefore(StatementProxy statement) {
          final String sql = statement.getBatchSql();
  
          final int batchSize = statement.getBatchSqlList().size();
          JdbcSqlStat sqlStat = statement.getSqlStat();
          if (sqlStat == null || sqlStat.isRemoved()) {
              sqlStat = createSqlStat(statement, sql);
              statement.setSqlStat(sqlStat);
          }
  
          if (sqlStat != null) {
              sqlStat.addExecuteBatchCount(batchSize);
          }
  
          internalBeforeStatementExecute(statement, sql);
  
      }
  
      @Override
      protected void statementExecuteBatchAfter(StatementProxy statement, int[] result) {
          internalAfterStatementExecute(statement, false, result);
  
      }
  
      private final void internalBeforeStatementExecute(StatementProxy statement, String sql) {
          JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
          dataSourceStat.getStatementStat().beforeExecute();
  
          final ConnectionProxy connection = statement.getConnectionProxy();
          final JdbcConnectionStat.Entry connectionCounter = getConnectionInfo(connection);
  
          statement.setLastExecuteStartNano();
  
          connectionCounter.setLastSql(sql);
  
          if (connectionStackTraceEnable) {
              connectionCounter.setLastStatementStatckTrace(new Exception());
          }
  
          // //////////SQL
  
          JdbcSqlStat sqlStat = statement.getSqlStat();
          if (sqlStat == null || sqlStat.isRemoved()) {
              sqlStat = createSqlStat(statement, sql);
              statement.setSqlStat(sqlStat);
          }
  
          JdbcStatContext statContext = JdbcStatManager.getInstance().getStatContext();
          if (statContext != null) {
              sqlStat.setName(statContext.getName());
              sqlStat.setFile(statContext.getFile());
          }
  
          boolean inTransaction = false;
          try {
              inTransaction = !statement.getConnectionProxy().getAutoCommit();
          } catch (SQLException e) {
              LOG.error("getAutoCommit error", e);
          }
  
          if (sqlStat != null) {
              sqlStat.setExecuteLastStartTime(System.currentTimeMillis());
              sqlStat.incrementRunningCount();
  
              if (inTransaction) {
                  sqlStat.incrementInTransactionCount();
              }
          }
  
          StatFilterContext.getInstance().executeBefore(sql, inTransaction);
  
          Profiler.enter(sql, Profiler.PROFILE_TYPE_SQL);
      }
  
      private final void internalAfterStatementExecute(StatementProxy statement, boolean firstResult,
                                                       int... updateCountArray) {
          final long nowNano = System.nanoTime();
          final long nanos = nowNano - statement.getLastExecuteStartNano();
  
          JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
          dataSourceStat.getStatementStat().afterExecute(nanos);
  
          final JdbcSqlStat sqlStat = statement.getSqlStat();
  
          if (sqlStat != null) {
              sqlStat.incrementExecuteSuccessCount();
  
              sqlStat.decrementRunningCount();
              sqlStat.addExecuteTime(statement.getLastExecuteType(), firstResult, nanos);
              statement.setLastExecuteTimeNano(nanos);
              if ((!statement.isFirstResultSet()) && statement.getLastExecuteType() == StatementExecuteType.Execute) {
                  try {
                      int updateCount = statement.getUpdateCount();
                      sqlStat.addUpdateCount(updateCount);
                  } catch (SQLException e) {
                      LOG.error("getUpdateCount error", e);
                  }
              } else {
                  for (int updateCount : updateCountArray) {
                      sqlStat.addUpdateCount(updateCount);
                      sqlStat.addFetchRowCount(0);
                      StatFilterContext.getInstance().addUpdateCount(updateCount);
                  }
              }
  
                long millis = nanos / (1000 * 1000);
              if (SQLTIME.get() != null) {
                  SQLTIME.get().addAndGet(millis);
              }
              if (millis >= slowSqlMillis) {
                  String slowParameters = buildSlowParameters(statement);
                  sqlStat.setLastSlowParameters(slowParameters);
  
                  if (logSlowSql) {
                      LOG.info("sql execute " + millis + " millis. \n" + statement.getLastExecuteSql() + "\n"
                              + slowParameters);
                  }
              }
          }
  
          String sql = statement.getLastExecuteSql();
          StatFilterContext.getInstance().executeAfter(sql, nanos, null);
  
          Profiler.release(nanos);
      }
  
      @Override
      protected void statement_executeErrorAfter(StatementProxy statement, String sql, Throwable error) {
  
          ConnectionProxy connection = statement.getConnectionProxy();
          JdbcConnectionStat.Entry connectionCounter = getConnectionInfo(connection);
  
          long nanos = System.nanoTime() - statement.getLastExecuteStartNano();
  
          JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
          dataSourceStat.getStatementStat().error(error);
          dataSourceStat.getStatementStat().afterExecute(nanos);
  
          connectionCounter.error(error);
  
          // SQL
          JdbcSqlStat sqlStat = statement.getSqlStat();
  
          if (sqlStat != null) {
              sqlStat.error(error);
              sqlStat.addExecuteTime(statement.getLastExecuteType(), statement.isFirstResultSet(), nanos);
              statement.setLastExecuteTimeNano(nanos);
          }
  
          StatFilterContext.getInstance().executeAfter(sql, nanos, error);
          Profiler.release(nanos);
      }
  
      private String buildSlowParameters(StatementProxy statement) {
          JSONWriter out = new JSONWriter();
  
          out.writeArrayStart();
          for (int i = 0, parametersSize = statement.getParametersSize(); i < parametersSize; ++i) {
              JdbcParameter parameter = statement.getParameter(i);
              if (i != 0) {
                  out.writeComma();
              }
              if (parameter == null) {
                  continue;
              }
  
              Object value = parameter.getValue();
              if (value == null) {
                  out.writeNull();
              } else if (value instanceof String) {
                  String text = (String) value;
                  if (text.length() > 100) {
                      out.writeString(text.substring(0, 97) + "...");
                  } else {
                      out.writeString(text);
                  }
              } else if (value instanceof Number) {
                  out.writeObject(value);
              } else if (value instanceof Date) {
                  out.writeObject(value);
              } else if (value instanceof Boolean) {
                  out.writeObject(value);
              } else if (value instanceof InputStream) {
                  out.writeString("<InputStream>");
              } else if (value instanceof NClob) {
                  out.writeString("<NClob>");
              } else if (value instanceof Clob) {
                  out.writeString("<Clob>");
              } else if (value instanceof Blob) {
                  out.writeString("<Blob>");
              } else {
                  out.writeString('<' + value.getClass().getName() + '>');
              }
          }
          out.writeArrayEnd();
  
          return out.toString();
      }
  
      @Override
      protected void resultSetOpenAfter(ResultSetProxy resultSet) {
          JdbcDataSourceStat dataSourceStat = resultSet.getStatementProxy().getConnectionProxy().getDirectDataSource().getDataSourceStat();
          dataSourceStat.getResultSetStat().beforeOpen();
  
          resultSet.setConstructNano();
  
          StatFilterContext.getInstance().resultSet_open();
      }
  
      @Override
      public void resultSet_close(FilterChain chain, ResultSetProxy resultSet) throws SQLException {
  
          long nanos = System.nanoTime() - resultSet.getConstructNano();
  
          int fetchRowCount = resultSet.getFetchRowCount();
  
          JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
          dataSourceStat.getResultSetStat().afterClose(nanos);
          dataSourceStat.getResultSetStat().addFetchRowCount(fetchRowCount);
          dataSourceStat.getResultSetStat().incrementCloseCounter();
  
          StatFilterContext.getInstance().addFetchRowCount(fetchRowCount);
  
          String sql = resultSet.getSql();
          if (sql != null) {
              JdbcSqlStat sqlStat = resultSet.getSqlStat();
              if (sqlStat != null && resultSet.getCloseCount() == 0) {
                  sqlStat.addFetchRowCount(fetchRowCount);
                  long stmtExecuteNano = resultSet.getStatementProxy().getLastExecuteTimeNano();
                  sqlStat.addResultSetHoldTimeNano(stmtExecuteNano, nanos);
                  if (resultSet.getReadStringLength() > 0) {
                      sqlStat.addStringReadLength(resultSet.getReadStringLength());
                  }
                  if (resultSet.getReadBytesLength() > 0) {
                      sqlStat.addReadBytesLength(resultSet.getReadBytesLength());
                  }
                  if (resultSet.getOpenInputStreamCount() > 0) {
                      sqlStat.addInputStreamOpenCount(resultSet.getOpenInputStreamCount());
                  }
                  if (resultSet.getOpenReaderCount() > 0) {
                      sqlStat.addReaderOpenCount(resultSet.getOpenReaderCount());
                  }
              }
          }
  
          chain.resultSet_close(resultSet);
  
          StatFilterContext.getInstance().resultSet_close(nanos);
      }
  
      public JdbcConnectionStat.Entry getConnectionInfo(ConnectionProxy connection) {
          JdbcConnectionStat.Entry counter = (JdbcConnectionStat.Entry) connection.getAttribute(ATTR_NAME_CONNECTION_STAT);
  
          if (counter == null) {
              String dataSourceName = connection.getDirectDataSource().getName();
              connection.putAttribute(ATTR_NAME_CONNECTION_STAT,
                      new JdbcConnectionStat.Entry(dataSourceName, connection.getId()));
              counter = (JdbcConnectionStat.Entry) connection.getAttribute(ATTR_NAME_CONNECTION_STAT);
          }
  
          return counter;
      }
  
      public JdbcSqlStat createSqlStat(StatementProxy statement, String sql) {
          DataSourceProxy dataSource = statement.getConnectionProxy().getDirectDataSource();
          JdbcDataSourceStat dataSourceStat = dataSource.getDataSourceStat();
  
          JdbcStatContext context = JdbcStatManager.getInstance().getStatContext();
          String contextSql = context != null ? context.getSql() : null;
          if (contextSql != null && contextSql.length() > 0) {
              return dataSourceStat.createSqlStat(contextSql);
          } else {
              String dbType = this.dbType;
  
              if (dbType == null) {
                  dbType = dataSource.getDbType();
              }
  
              sql = mergeSql(sql, dbType);
              return dataSourceStat.createSqlStat(sql);
          }
      }
  
      public static StatFilter getStatFilter(DataSourceProxy dataSource) {
          for (Filter filter : dataSource.getProxyFilters()) {
              if (filter instanceof StatFilter) {
                  return (StatFilter) filter;
              }
          }
  
          return null;
      }
  
      @Override
      public void dataSource_releaseConnection(FilterChain chain, DruidPooledConnection conn) throws SQLException {
          chain.dataSource_recycle(conn);
  
          long nanos = System.nanoTime() - conn.getConnectedTimeNano();
  
          long millis = nanos / (1000L * 1000L);
  
          JdbcDataSourceStat dataSourceStat = chain.getDataSource().getDataSourceStat();
          dataSourceStat.getConnectionHoldHistogram().record(millis);
  
          StatFilterContext.getInstance().pool_connection_close(nanos);
      }
  
      @Override
      public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource,
                                                            long maxWaitMillis) throws SQLException {
          DruidPooledConnection conn = chain.dataSource_connect(dataSource, maxWaitMillis);
  
          if (conn != null) {
              conn.setConnectedTimeNano();
  
              StatFilterContext.getInstance().pool_connection_open();
          }
  
          return conn;
      }
  
      @Override
      public Clob resultSet_getClob(FilterChain chain, ResultSetProxy resultSet, int columnIndex) throws SQLException {
          Clob clob = chain.resultSet_getClob(resultSet, columnIndex);
  
          if (clob != null) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), resultSet, (ClobProxy) clob);
          }
  
          return clob;
      }
  
      @Override
      public Clob resultSet_getClob(FilterChain chain, ResultSetProxy resultSet, String columnLabel) throws SQLException {
          Clob clob = chain.resultSet_getClob(resultSet, columnLabel);
  
          if (clob != null) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), resultSet, (ClobProxy) clob);
          }
  
          return clob;
      }
  
      @Override
      public Blob callableStatement_getBlob(FilterChain chain, CallableStatementProxy statement, int parameterIndex)
              throws SQLException {
          Blob blob = chain.callableStatement_getBlob(statement, parameterIndex);
  
          if (blob != null) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, blob);
          }
  
          return blob;
      }
  
      @Override
      public Blob callableStatement_getBlob(FilterChain chain, CallableStatementProxy statement, String parameterName)
              throws SQLException {
          Blob blob = chain.callableStatement_getBlob(statement, parameterName);
  
          if (blob != null) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, blob);
          }
  
          return blob;
      }
  
      @Override
      public Blob resultSet_getBlob(FilterChain chain, ResultSetProxy result, int columnIndex) throws SQLException {
          Blob blob = chain.resultSet_getBlob(result, columnIndex);
  
          if (blob != null) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), result, blob);
          }
  
          return blob;
      }
  
      @Override
      public Blob resultSet_getBlob(FilterChain chain, ResultSetProxy result, String columnLabel) throws SQLException {
          Blob blob = chain.resultSet_getBlob(result, columnLabel);
  
          if (blob != null) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), result, blob);
          }
  
          return blob;
      }
  
      @Override
      public Clob callableStatement_getClob(FilterChain chain, CallableStatementProxy statement, int parameterIndex)
              throws SQLException {
          Clob clob = chain.callableStatement_getClob(statement, parameterIndex);
  
          if (clob != null) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (ClobProxy) clob);
          }
  
          return clob;
      }
  
      @Override
      public Clob callableStatement_getClob(FilterChain chain, CallableStatementProxy statement, String parameterName)
              throws SQLException {
          Clob clob = chain.callableStatement_getClob(statement, parameterName);
  
          if (clob != null) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (ClobProxy) clob);
          }
  
          return clob;
      }
  
      @Override
      public Object resultSet_getObject(FilterChain chain, ResultSetProxy result, int columnIndex) throws SQLException {
          Object obj = chain.resultSet_getObject(result, columnIndex);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (Blob) obj);
          } else if (obj instanceof String) {
              result.addReadStringLength(((String) obj).length());
          }
  
          return obj;
      }
  
      @Override
      public Object resultSet_getObject(FilterChain chain, ResultSetProxy result, int columnIndex,
                                        java.util.Map<String, Class<?>> map) throws SQLException {
          Object obj = chain.resultSet_getObject(result, columnIndex, map);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (Blob) obj);
          } else if (obj instanceof String) {
              result.addReadStringLength(((String) obj).length());
          }
  
          return obj;
      }
  
      @Override
      public Object resultSet_getObject(FilterChain chain, ResultSetProxy result, String columnLabel) throws SQLException {
          Object obj = chain.resultSet_getObject(result, columnLabel);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (Blob) obj);
          } else if (obj instanceof String) {
              result.addReadStringLength(((String) obj).length());
          }
  
          return obj;
      }
  
      @Override
      public Object resultSet_getObject(FilterChain chain, ResultSetProxy result, String columnLabel,
                                        java.util.Map<String, Class<?>> map) throws SQLException {
          Object obj = chain.resultSet_getObject(result, columnLabel, map);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), result, (Blob) obj);
          } else if (obj instanceof String) {
              result.addReadStringLength(((String) obj).length());
          }
  
          return obj;
      }
  
      @Override
      public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, int parameterIndex)
              throws SQLException {
          Object obj = chain.callableStatement_getObject(statement, parameterIndex);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (Blob) obj);
          }
  
          return obj;
      }
  
      @Override
      public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, int parameterIndex,
                                                java.util.Map<String, Class<?>> map) throws SQLException {
          Object obj = chain.callableStatement_getObject(statement, parameterIndex, map);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (Blob) obj);
          }
  
          return obj;
      }
  
      @Override
      public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, String parameterName)
              throws SQLException {
          Object obj = chain.callableStatement_getObject(statement, parameterName);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (Blob) obj);
          }
  
          return obj;
      }
  
      @Override
      public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement,
                                                String parameterName, java.util.Map<String, Class<?>> map)
              throws SQLException {
          Object obj = chain.callableStatement_getObject(statement, parameterName, map);
  
          if (obj instanceof Clob) {
              clobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (ClobProxy) obj);
          } else if (obj instanceof Blob) {
              blobOpenAfter(chain.getDataSource().getDataSourceStat(), statement, (Blob) obj);
          }
  
          return obj;
      }
  
      private void blobOpenAfter(JdbcDataSourceStat dataSourceStat, ResultSetProxy rs, Blob blob) {
          blobOpenAfter(dataSourceStat, rs.getStatementProxy(), blob);
      }
  
      private void clobOpenAfter(JdbcDataSourceStat dataSourceStat, ResultSetProxy rs, ClobProxy clob) {
          clobOpenAfter(dataSourceStat, rs.getStatementProxy(), clob);
      }
  
      private void blobOpenAfter(JdbcDataSourceStat dataSourceStat, StatementProxy stmt, Blob blob) {
          dataSourceStat.incrementBlobOpenCount();
  
          if (stmt != null) {
              JdbcSqlStat sqlStat = stmt.getSqlStat();
              if (sqlStat != null) {
                  sqlStat.incrementBlobOpenCount();
              }
          }
  
          StatFilterContext.getInstance().blob_open();
      }
  
      private void clobOpenAfter(JdbcDataSourceStat dataSourceStat, StatementProxy stmt, ClobProxy clob) {
          dataSourceStat.incrementClobOpenCount();
  
          if (stmt != null) {
              JdbcSqlStat sqlStat = stmt.getSqlStat();
              if (sqlStat != null) {
                  sqlStat.incrementClobOpenCount();
              }
          }
  
          StatFilterContext.getInstance().clob_open();
      }
  
      @Override
      public String resultSet_getString(FilterChain chain, ResultSetProxy result, int columnIndex) throws SQLException {
          String value = chain.resultSet_getString(result, columnIndex);
  
          if (value != null) {
              result.addReadStringLength(value.length());
          }
  
          return value;
      }
  
      @Override
      public String resultSet_getString(FilterChain chain, ResultSetProxy result, String columnLabel) throws SQLException {
          String value = chain.resultSet_getString(result, columnLabel);
  
          if (value != null) {
              result.addReadStringLength(value.length());
          }
  
          return value;
      }
  
      @Override
      public byte[] resultSet_getBytes(FilterChain chain, ResultSetProxy result, int columnIndex) throws SQLException {
          byte[] value = chain.resultSet_getBytes(result, columnIndex);
  
          if (value != null) {
              result.addReadBytesLength(value.length);
          }
  
          return value;
      }
  
      @Override
      public byte[] resultSet_getBytes(FilterChain chain, ResultSetProxy result, String columnLabel) throws SQLException {
          byte[] value = chain.resultSet_getBytes(result, columnLabel);
  
          if (value != null) {
              result.addReadBytesLength(value.length);
          }
  
          return value;
      }
  
      @Override
      public InputStream resultSet_getBinaryStream(FilterChain chain, ResultSetProxy result, int columnIndex)
              throws SQLException {
          InputStream input = chain.resultSet_getBinaryStream(result, columnIndex);
  
          if (input != null) {
              result.incrementOpenInputStreamCount();
          }
  
          return input;
      }
  
      @Override
      public InputStream resultSet_getBinaryStream(FilterChain chain, ResultSetProxy result, String columnLabel)
              throws SQLException {
          InputStream input = chain.resultSet_getBinaryStream(result, columnLabel);
  
          if (input != null) {
              result.incrementOpenInputStreamCount();
          }
  
          return input;
      }
  
      @Override
      public InputStream resultSet_getAsciiStream(FilterChain chain, ResultSetProxy result, int columnIndex)
              throws SQLException {
          InputStream input = chain.resultSet_getAsciiStream(result, columnIndex);
  
          if (input != null) {
              result.incrementOpenInputStreamCount();
          }
  
          return input;
      }
  
      @Override
      public InputStream resultSet_getAsciiStream(FilterChain chain, ResultSetProxy result, String columnLabel)
              throws SQLException {
          InputStream input = chain.resultSet_getAsciiStream(result, columnLabel);
  
          if (input != null) {
              result.incrementOpenInputStreamCount();
          }
  
          return input;
      }
  
      @Override
      public Reader resultSet_getCharacterStream(FilterChain chain, ResultSetProxy result, int columnIndex)
              throws SQLException {
          Reader reader = chain.resultSet_getCharacterStream(result, columnIndex);
  
          if (reader != null) {
              result.incrementOpenReaderCount();
          }
  
          return reader;
      }
  
      @Override
      public Reader resultSet_getCharacterStream(FilterChain chain, ResultSetProxy result, String columnLabel)
              throws SQLException {
          Reader reader = chain.resultSet_getCharacterStream(result, columnLabel);
  
          if (reader != null) {
              result.incrementOpenReaderCount();
          }
  
          return reader;
      }
  
  }
  