/** {@inheritDoc} */
  @Override
  public int executeUpdate() throws SQLException {
    if ((this.sqlStream == null) && !this.debug) {
      return this.statement.executeUpdate();
    }

    if (this.statementNo == -1) {
      this.statementNo = PreparedStatementProxy.no.incrementAndGet();
    }

    this.executionNo++;

    PreparedStatementProxy.LOG.debug(
        "{0}:{1} executeUpdate(){2}",
        this.statementNo,
        this.executionNo,
        PreparedStatementProxy.LOG.lazyBoxed(this.sql, this.parameters));
    if (this.sqlStream != null) {
      this.sqlStream.println(
          MessageFormat.format(
              "{0}:{1} executeUpdate(){2}",
              this.statementNo,
              this.executionNo,
              PreparedStatementProxy.LOG.lazyBoxed(this.sql, this.parameters)));
    }

    final long start = System.currentTimeMillis();
    try {
      return this.statement.executeUpdate();
    } finally {
      final long time = System.currentTimeMillis() - start;
      if (time > this.slowSqlThreshold) {
        if (this.sqlStream != null) {
          this.sqlStream.println(
              MessageFormat.format(
                  "{0}:{1} {2} msecs, executeUpdate()", this.statementNo, this.executionNo, time));

          new OperationTookLongTimeWarning().printStackTrace(this.sqlStream);
        }

        PreparedStatementProxy.LOG.warn(
            new OperationTookLongTimeWarning(),
            "{0}:{1} {2} msecs, executeUpdate()",
            this.statementNo,
            this.executionNo,
            time);
      } else {
        if (this.sqlStream != null) {
          this.sqlStream.println(
              MessageFormat.format(
                  "{0}:{1} {2} msecs, executeUpdate()", this.statementNo, this.executionNo, time));
        }

        PreparedStatementProxy.LOG.debug(
            "{0}:{1} {2} msecs, executeUpdate()", this.statementNo, this.executionNo, time);
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public ResultSet executeQuery() throws SQLException {
    if ((this.sqlStream == null) && !this.debug) {
      return this.statement.executeQuery();
    }

    if (this.statementNo == -1) {
      this.statementNo = PreparedStatementProxy.no.incrementAndGet();
    }

    this.executionNo++;

    PreparedStatementProxy.LOG.debug(
        "{0}:{1} executeQuery(){2}",
        this.statementNo,
        this.executionNo,
        PreparedStatementProxy.LOG.lazyBoxed(this.sql, this.parameters));

    final long start = System.currentTimeMillis();
    try {
      return this.statement.executeQuery();
    } finally {
      final long time = System.currentTimeMillis() - start;

      if (time > this.slowSqlThreshold) {
        PreparedStatementProxy.LOG.warn(
            new OperationTookLongTimeWarning(),
            "{0}:{1} {2} msecs, executeQuery()",
            this.statementNo,
            this.executionNo,
            time);
      } else {
        PreparedStatementProxy.LOG.trace(
            "{0}:{1} {2} msecs, executeQuery()", this.statementNo, this.executionNo, time);
      }
    }
  }
  /**
   * @param sql the SQL
   * @param statement the delegate statement
   * @param slowSqlThreshold the time to decide if SQL is deemed as slow
   * @param sqlLoggingType the type of the sql logging
   * @since $version
   * @author hceylan
   */
  public PreparedStatementProxy(
      String sql,
      PreparedStatement statement,
      long slowSqlThreshold,
      SqlLoggingType sqlLoggingType) {
    super();

    this.sql = sql;
    this.statement = statement;
    this.slowSqlThreshold = slowSqlThreshold;

    switch (sqlLoggingType) {
      case STDERR:
        this.sqlStream = System.err;
        break;
      case STDOUT:
        this.sqlStream = System.out;
        break;
      default:
        this.sqlStream = null;
    }

    this.debug = PreparedStatementProxy.LOG.isDebugEnabled();
  }
  /**
   * Resets the prepared statement and returns itself
   *
   * @return self
   * @since $version
   * @author hceylan
   */
  public PreparedStatement reset() {
    this.debug = PreparedStatementProxy.LOG.isDebugEnabled();

    return this;
  }