    001    /**
    002     * Copyright 2007-2008 Arthur Blake
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License");
    005     * you may not use this file except in compliance with the License.
    006     * You may obtain a copy of the License at
    007     *
    008     *    http://www.apache.org/licenses/LICENSE-2.0
    009     *
    010     * Unless required by applicable law or agreed to in writing, software
    011     * distributed under the License is distributed on an "AS IS" BASIS,
    012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013     * See the License for the specific language governing permissions and
    014     * limitations under the License.
    015     */
    016    package net.sf.log4jdbc;
    017
    018    import java.io.InputStream;
    019    import java.io.Reader;
    020    import java.math.BigDecimal;
    021    import java.net.URL;
    022    import java.sql.*;
    023    import java.util.ArrayList;
    024    import java.util.Calendar;
    025    import java.util.StringTokenizer;
    026    import java.util.List;
    027
    028    /**
    029     * Wraps a PreparedStatement and reports method calls, returns and exceptions.
    030     *
    031     * @author Arthur Blake
    032     */
    033    public class PreparedStatementSpy extends StatementSpy implements PreparedStatement
    034    {
    035
    036      private final SpyLogDelegator log;
    037
    038      /**
    039       * holds list of bind variables for tracing
    040       */
    041      protected final List argTrace = new ArrayList();
    042
    043      // a way to turn on and off type help...
    044      // todo:  make this a configurable parameter
    045      // todo, debug arrays and streams in a more useful manner.... if possible
    046      private static final boolean showTypeHelp = false;
    047
    048      /**
    049       * Store an argument (bind variable) into the argTrace list (above) for later dumping.
    050       *
    051       * @param i          index of argument being set.
    052       * @param typeHelper optional additional info about the type that is being set in the arg
    053       * @param arg        argument being bound.
    054       */
    055      protected void argTraceSet(int i, String typeHelper, Object arg)
    056      {
    057        i--;  // make the index 0 based
    058        synchronized (argTrace)
    059        {
    060          // if an object is being inserted out of sequence, fill up missing values with null...
    061          while (i >= argTrace.size())
    062          {
    063            argTrace.add(argTrace.size(), null);
    064          }
    065          if (!showTypeHelp || typeHelper == null)
    066          {
    067            typeHelper = "";
    068          }
    069          if (arg != null)
    070          {
    071            argTrace.set(i, typeHelper + arg.toString());
    072          }
    073          else
    074          {
    075            argTrace.set(i, typeHelper + "null");
    076          }
    077        }
    078      }
    079
    080      private String sql;
    081
    082      protected String dumpedSql()
    083      {
    084        StringBuffer dumpSql = new StringBuffer();
    085        int lastPos = 0;
    086        int Qpos = sql.indexOf('?', lastPos);  // find position of first question mark
    087        int argIdx = 0;
    088        String arg;
    089
    090        while (Qpos != -1)
    091        {
    092          // get stored argument
    093          synchronized (argTrace)
    094          {
    095            try
    096            {
    097              arg = (String) argTrace.get(argIdx);
    098            }
    099            catch (IndexOutOfBoundsException e)
    100            {
    101              arg = "?";
    102            }
    103          }
    104          if (arg == null)
    105          {
    106            arg = "?";
    107          }
    108
    109          argIdx++;
    110
    111          dumpSql.append(sql.substring(lastPos, Qpos));  // dump segment of sql up to question mark.
    112          lastPos = Qpos + 1;
    113          Qpos = sql.indexOf('?', lastPos);
    114          dumpSql.append(arg);
    115        }
    116        if (lastPos < sql.length())
    117        {
    118          dumpSql.append(sql.substring(lastPos, sql.length()));  // dump last segment
    119        }
    120
    121        // insert line breaks into sql to make it more readable
    122        StringBuffer output = new StringBuffer();
    123        StringTokenizer st = new StringTokenizer(dumpSql.toString());
    124
    125        String token;
    126        int linelength = 0;
    127
    128        while (st.hasMoreElements())
    129        {
    130          token = (String) st.nextElement();
    131
    132          output.append(token);
    133          linelength += token.length();
    134          output.append(" ");
    135          linelength++;
    136          if (linelength > 90)
    137          {
    138            output.append("\n");
    139            linelength = 0;
    140          }
    141        }
    142
    143        return output.toString();
    144      }
    145
    146      protected void reportAllReturns(String methodCall, String msg)
    147      {
    148        log.methodReturned(this, methodCall, msg);
    149      }
    150
    151      /**
    152       * The real PreparedStatement that this PreparedStatementSpy wraps.
    153       */
    154      protected PreparedStatement realPreparedStatement;
    155
    156      /**
    157       * RdbmsSpecifics for formatting SQL for the given RDBMS.
    158       */
    159      protected RdbmsSpecifics rdbmsSpecifics;
    160
    161      /**
    162       * Create a PreparedStatementSpy (JDBC 4.0 version) for logging activity of another PreparedStatement.
    163       *
    164       * @param sql                   SQL for the prepared statement that is being spied upon.
    165       * @param connectionSpy         ConnectionSpy that was called to produce this PreparedStatement.
    166       * @param realPreparedStatement The actual PreparedStatement that is being spied upon.
    167       */
    168      public PreparedStatementSpy(String sql, ConnectionSpy connectionSpy, PreparedStatement realPreparedStatement)
    169      {
    170        super(connectionSpy, realPreparedStatement);  // does null check for us
    171        this.sql = sql;
    172        this.realPreparedStatement = realPreparedStatement;
    173        log = SpyLogFactory.getSpyLogDelegator();
    174        rdbmsSpecifics = connectionSpy.getRdbmsSpecifics();
    175      }
    176
    177      public String getClassType()
    178      {
    179        return "PreparedStatement";
    180      }
    181
    182      // forwarding methods
    183
    184      public void setTime(int parameterIndex, Time x) throws SQLException
    185      {
    186        String methodCall = "setTime(" + parameterIndex + ", " + x + ")";
    187        argTraceSet(parameterIndex, "(Time)", x);
    188        try
    189        {
    190          realPreparedStatement.setTime(parameterIndex, x);
    191        }
    192        catch (SQLException s)
    193        {
    194          reportException(methodCall, s);
    195          throw s;
    196        }
    197        reportReturn(methodCall);
    198      }
    199
    200      public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException
    201      {
    202        String methodCall = "setTime(" + parameterIndex + ", " + x + ", " + cal + ")";
    203        argTraceSet(parameterIndex, "(Time)", x);
    204        try
    205        {
    206          realPreparedStatement.setTime(parameterIndex, x, cal);
    207        }
    208        catch (SQLException s)
    209        {
    210          reportException(methodCall, s);
    211          throw s;
    212        }
    213        reportReturn(methodCall);
    214      }
    215
    216      public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException
    217      {
    218        String methodCall = "setCharacterStream(" + parameterIndex + ", " + reader + ", " + length + ")";
    219        argTraceSet(parameterIndex, "(Reader)", "<Reader of length " + length + ">");
    220        try
    221        {
    222          realPreparedStatement.setCharacterStream(parameterIndex, reader, length);
    223        }
    224        catch (SQLException s)
    225        {
    226          reportException(methodCall, s);
    227          throw s;
    228        }
    229        reportReturn(methodCall);
    230      }
    231
    232      public void setNull(int parameterIndex, int sqlType) throws SQLException
    233      {
    234        String methodCall = "setNull(" + parameterIndex + ", " + sqlType + ")";
    235        argTraceSet(parameterIndex, null, "null");
    236        try
    237        {
    238          realPreparedStatement.setNull(parameterIndex, sqlType);
    239        }
    240        catch (SQLException s)
    241        {
    242          reportException(methodCall, s);
    243          throw s;
    244        }
    245        reportReturn(methodCall);
    246      }
    247
    248      public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException
    249      {
    250        String methodCall = "setNull(" + paramIndex + ", " + sqlType + ", " + typeName + ")";
    251        argTraceSet(paramIndex, null, "null");
    252        try
    253        {
    254          realPreparedStatement.setNull(paramIndex, sqlType, typeName);
    255        }
    256        catch (SQLException s)
    257        {
    258          reportException(methodCall, s);
    259          throw s;
    260        }
    261        reportReturn(methodCall);
    262      }
    263
    264      public void setRef(int i, Ref x) throws SQLException
    265      {
    266        String methodCall = "setRef(" + i + ", " + x + ")";
    267        argTraceSet(i, "(Ref)", x);
    268        try
    269        {
    270          realPreparedStatement.setRef(i, x);
    271        }
    272        catch (SQLException s)
    273        {
    274          reportException(methodCall, s);
    275          throw s;
    276        }
    277        reportReturn(methodCall);
    278      }
    279
    280      public void setBoolean(int parameterIndex, boolean x) throws SQLException
    281      {
    282        String methodCall = "setBoolean(" + parameterIndex + ", " + x + ")";
    283        argTraceSet(parameterIndex, "(boolean)", Boolean.toString(x));
    284        try
    285        {
    286          realPreparedStatement.setBoolean(parameterIndex, x);
    287        }
    288        catch (SQLException s)
    289        {
    290          reportException(methodCall, s);
    291          throw s;
    292        }
    293        reportReturn(methodCall);
    294      }
    295
    296      public void setBlob(int i, Blob x) throws SQLException
    297      {
    298        String methodCall = "setBlob(" + i + ", " + x + ")";
    299        argTraceSet(i, "(Blob)", "<Blob of size " + x.length() + ">");
    300        try
    301        {
    302          realPreparedStatement.setBlob(i, x);
    303        }
    304        catch (SQLException s)
    305        {
    306          reportException(methodCall, s);
    307          throw s;
    308        }
    309        reportReturn(methodCall);
    310      }
    311
    312      public void setClob(int i, Clob x) throws SQLException
    313      {
    314        String methodCall = "setClob(" + i + ", " + x + ")";
    315        argTraceSet(i, "(Clob)", "<Clob of size " + x.length() + ">");
    316        try
    317        {
    318          realPreparedStatement.setClob(i, x);
    319        }
    320        catch (SQLException s)
    321        {
    322          reportException(methodCall, s);
    323          throw s;
    324        }
    325        reportReturn(methodCall);
    326      }
    327
    328      public void setArray(int i, Array x) throws SQLException
    329      {
    330        String methodCall = "setArray(" + i + ", " + x + ")";
    331        argTraceSet(i, "(Array)", "<Array>");
    332        try
    333        {
    334          realPreparedStatement.setArray(i, x);
    335        }
    336        catch (SQLException s)
    337        {
    338          reportException(methodCall, s);
    339          throw s;
    340        }
    341        reportReturn(methodCall);
    342      }
    343
    344      public void setByte(int parameterIndex, byte x) throws SQLException
    345      {
    346        String methodCall = "setByte(" + parameterIndex + ", " + x + ")";
    347        argTraceSet(parameterIndex, "(byte)", Byte.toString(x));
    348        try
    349        {
    350          realPreparedStatement.setByte(parameterIndex, x);
    351        }
    352        catch (SQLException s)
    353        {
    354          reportException(methodCall, s);
    355          throw s;
    356        }
    357        reportReturn(methodCall);
    358      }
    359
    360      /**
    361       * @deprecated
    362       */
    363      public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
    364      {
    365        String methodCall = "setUnicodeStream(" + parameterIndex + ", " + x + ", " + length + ")";
    366        argTraceSet(parameterIndex, "(Unicode InputStream)", "<Unicode InputStream of length " + length + ">");
    367        try
    368        {
    369          realPreparedStatement.setUnicodeStream(parameterIndex, x, length);
    370        }
    371        catch (SQLException s)
    372        {
    373          reportException(methodCall, s);
    374          throw s;
    375        }
    376        reportReturn(methodCall);
    377      }
    378
    379      public void setShort(int parameterIndex, short x) throws SQLException
    380      {
    381        String methodCall = "setShort(" + parameterIndex + ", " + x + ")";
    382        argTraceSet(parameterIndex, "(short)", Short.toString(x));
    383        try
    384        {
    385          realPreparedStatement.setShort(parameterIndex, x);
    386        }
    387        catch (SQLException s)
    388        {
    389          reportException(methodCall, s);
    390          throw s;
    391        }
    392        reportReturn(methodCall);
    393      }
    394
    395      public boolean execute() throws SQLException
    396      {
    397        String methodCall = "execute()";
    398        String dumpedSql = dumpedSql();
    399        reportSql(dumpedSql, methodCall);
    400        long tstart = System.currentTimeMillis();
    401        try
    402        {
    403          boolean result = realPreparedStatement.execute();
    404          reportSqlTiming(System.currentTimeMillis() - tstart, dumpedSql, methodCall);
    405          return reportReturn(methodCall, result);
    406        }
    407        catch (SQLException s)
    408        {
    409          reportException(methodCall, s, dumpedSql, System.currentTimeMillis() - tstart);
    410          throw s;
    411        }
    412      }
    413
    414      public void setInt(int parameterIndex, int x) throws SQLException
    415      {
    416        String methodCall = "setInt(" + parameterIndex + ", " + x + ")";
    417        argTraceSet(parameterIndex, "(int)", Integer.toString(x));
    418        try
    419        {
    420          realPreparedStatement.setInt(parameterIndex, x);
    421        }
    422        catch (SQLException s)
    423        {
    424          reportException(methodCall, s);
    425          throw s;
    426        }
    427        reportReturn(methodCall);
    428      }
    429
    430      public void setLong(int parameterIndex, long x) throws SQLException
    431      {
    432        String methodCall = "setLong(" + parameterIndex + ", " + x + ")";
    433        argTraceSet(parameterIndex, "(long)", Long.toString(x));
    434        try
    435        {
    436          realPreparedStatement.setLong(parameterIndex, x);
    437        }
    438        catch (SQLException s)
    439        {
    440          reportException(methodCall, s);
    441          throw s;
    442        }
    443        reportReturn(methodCall);
    444      }
    445
    446      public void setFloat(int parameterIndex, float x) throws SQLException
    447      {
    448        String methodCall = "setFloat(" + parameterIndex + ", " + x + ")";
    449        argTraceSet(parameterIndex, "(float)", Float.toString(x));
    450        try
    451        {
    452          realPreparedStatement.setFloat(parameterIndex, x);
    453        }
    454        catch (SQLException s)
    455        {
    456          reportException(methodCall, s);
    457          throw s;
    458        }
    459        reportReturn(methodCall);
    460      }
    461
    462      public void setDouble(int parameterIndex, double x) throws SQLException
    463      {
    464        String methodCall = "setDouble(" + parameterIndex + ", " + x + ")";
    465        argTraceSet(parameterIndex, "(double)", Double.toString(x));
    466        try
    467        {
    468          realPreparedStatement.setDouble(parameterIndex, x);
    469        }
    470        catch (SQLException s)
    471        {
    472          reportException(methodCall, s);
    473          throw s;
    474        }
    475        reportReturn(methodCall);
    476      }
    477
    478      public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException
    479      {
    480        String methodCall = "setBigDecimal(" + parameterIndex + ", " + x + ")";
    481        argTraceSet(parameterIndex, "(BigDecimal)", x);
    482        try
    483        {
    484          realPreparedStatement.setBigDecimal(parameterIndex, x);
    485        }
    486        catch (SQLException s)
    487        {
    488          reportException(methodCall, s);
    489          throw s;
    490        }
    491        reportReturn(methodCall);
    492      }
    493
    494      public void setURL(int parameterIndex, URL x) throws SQLException
    495      {
    496        String methodCall = "setURL(" + parameterIndex + ", " + x + ")";
    497        argTraceSet(parameterIndex, "(URL)", x);
    498
    499        try
    500        {
    501          realPreparedStatement.setURL(parameterIndex, x);
    502        }
    503        catch (SQLException s)
    504        {
    505          reportException(methodCall, s);
    506          throw s;
    507        }
    508        reportReturn(methodCall);
    509      }
    510
    511      public void setString(int parameterIndex, String x) throws SQLException
    512      {
    513        String methodCall = "setString(" + parameterIndex + ", \"" + x + "\")";
    514        argTraceSet(parameterIndex, "(String)", rdbmsSpecifics.formatParameterObject(x));
    515        try
    516        {
    517          realPreparedStatement.setString(parameterIndex, x);
    518        }
    519        catch (SQLException s)
    520        {
    521          reportException(methodCall, s);
    522          throw s;
    523        }
    524        reportReturn(methodCall);
    525      }
    526
    527      public void setBytes(int parameterIndex, byte[] x) throws SQLException
    528      {
    529        //todo: dump array?
    530        String methodCall = "setBytes(" + parameterIndex + ", " + x + ")";
    531        argTraceSet(parameterIndex, "(byte[])", "<byte[]>");
    532        try
    533        {
    534          realPreparedStatement.setBytes(parameterIndex, x);
    535        }
    536        catch (SQLException s)
    537        {
    538          reportException(methodCall, s);
    539          throw s;
    540        }
    541        reportReturn(methodCall);
    542      }
    543
    544      public void setDate(int parameterIndex, Date x) throws SQLException
    545      {
    546        String methodCall = "setDate(" + parameterIndex + ", " + x + ")";
    547        argTraceSet(parameterIndex, "(Date)", rdbmsSpecifics.formatParameterObject(x));
    548        try
    549        {
    550          realPreparedStatement.setDate(parameterIndex, x);
    551        }
    552        catch (SQLException s)
    553        {
    554          reportException(methodCall, s);
    555          throw s;
    556        }
    557        reportReturn(methodCall);
    558      }
    559
    560      public ParameterMetaData getParameterMetaData() throws SQLException
    561      {
    562        String methodCall = "getParameterMetaData()";
    563        try
    564        {
    565          return (ParameterMetaData) reportReturn(methodCall, realPreparedStatement.getParameterMetaData());
    566        }
    567        catch (SQLException s)
    568        {
    569          reportException(methodCall, s);
    570          throw s;
    571        }
    572      }
    573
    574      public void setRowId(int parameterIndex, RowId x) throws SQLException {
    575        String methodCall = "setRowId(" + parameterIndex + ", " + x + ")";
    576        argTraceSet(parameterIndex, "(RowId)", rdbmsSpecifics.formatParameterObject(x));
    577        try
    578        {
    579          realPreparedStatement.setRowId(parameterIndex, x);
    580        }
    581        catch (SQLException s)
    582        {
    583          reportException(methodCall, s);
    584          throw s;
    585        }
    586        reportReturn(methodCall);
    587      }
    588
    589      public void setNString(int parameterIndex, String value) throws SQLException {
    590        String methodCall = "setNString(" + parameterIndex + ", " + value + ")";
    591        argTraceSet(parameterIndex, "(String)", rdbmsSpecifics.formatParameterObject(value));
    592        try
    593        {
    594          realPreparedStatement.setNString(parameterIndex, value);
    595        }
    596        catch (SQLException s)
    597        {
    598          reportException(methodCall, s);
    599          throw s;
    600        }
    601        reportReturn(methodCall);
    602      }
    603
    604      public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
    605        String methodCall = "setNCharacterStream(" + parameterIndex + ", " + value + ", " + length + ")";
    606        argTraceSet(parameterIndex, "(Reader)", "<Reader of length " + length + ">");
    607        try
    608        {
    609          realPreparedStatement.setNCharacterStream(parameterIndex, value, length);
    610        }
    611        catch (SQLException s)
    612        {
    613          reportException(methodCall, s);
    614          throw s;
    615        }
    616        reportReturn(methodCall);
    617      }
    618
    619      public void setNClob(int parameterIndex, NClob value) throws SQLException {
    620        String methodCall = "setNClob(" + parameterIndex + ", " + value + ")";
    621        argTraceSet(parameterIndex, "(NClob)", "<NClob>");
    622        try
    623        {
    624          realPreparedStatement.setNClob(parameterIndex, value);
    625        }
    626        catch (SQLException s)
    627        {
    628          reportException(methodCall, s);
    629          throw s;
    630        }
    631        reportReturn(methodCall);
    632      }
    633
    634      public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
    635        String methodCall = "setClob(" + parameterIndex + ", " + reader + ", " + length + ")";
    636        argTraceSet(parameterIndex, "(Reader)", "<Reader of length " + length + ">");
    637        try
    638        {
    639          realPreparedStatement.setClob(parameterIndex, reader, length);
    640        }
    641        catch (SQLException s)
    642        {
    643          reportException(methodCall, s);
    644          throw s;
    645        }
    646        reportReturn(methodCall);
    647      }
    648
    649      public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
    650        String methodCall = "setBlob(" + parameterIndex + ", " + inputStream + ", " + length + ")";
    651        argTraceSet(parameterIndex, "(InputStream)", "<InputStream of length " + length + ">");
    652        try
    653        {
    654          realPreparedStatement.setBlob(parameterIndex, inputStream, length);
    655        }
    656        catch (SQLException s)
    657        {
    658          reportException(methodCall, s);
    659          throw s;
    660        }
    661        reportReturn(methodCall);
    662      }
    663
    664      public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
    665        String methodCall = "setNClob(" + parameterIndex + ", " + reader + ", " + length + ")";
    666        argTraceSet(parameterIndex, "(Reader)", "<Reader of length " + length + ">");
    667        try
    668        {
    669          realPreparedStatement.setNClob(parameterIndex, reader, length);
    670        }
    671        catch (SQLException s)
    672        {
    673          reportException(methodCall, s);
    674          throw s;
    675        }
    676        reportReturn(methodCall);
    677      }
    678
    679      public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
    680        String methodCall = "setSQLXML(" + parameterIndex + ", " + xmlObject + ")";
    681        argTraceSet(parameterIndex, "(SQLXML)", rdbmsSpecifics.formatParameterObject(xmlObject));
    682        try
    683        {
    684          realPreparedStatement.setSQLXML(parameterIndex, xmlObject);
    685        }
    686        catch (SQLException s)
    687        {
    688          reportException(methodCall, s);
    689          throw s;
    690        }
    691        reportReturn(methodCall);
    692      }
    693
    694      public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException
    695      {
    696        String methodCall = "setDate(" + parameterIndex + ", " + x + ", " + cal + ")";
    697        argTraceSet(parameterIndex, "(Date)", rdbmsSpecifics.formatParameterObject(x));
    698
    699        try
    700        {
    701          realPreparedStatement.setDate(parameterIndex, x, cal);
    702        }
    703        catch (SQLException s)
    704        {
    705          reportException(methodCall, s);
    706          throw s;
    707        }
    708        reportReturn(methodCall);
    709      }
    710
    711      public ResultSet executeQuery() throws SQLException
    712      {
    713        String methodCall = "executeQuery()";
    714        String dumpedSql = dumpedSql();
    715        reportSql(dumpedSql, methodCall);
    716        long tstart = System.currentTimeMillis();
    717        try
    718        {
    719          ResultSet r = realPreparedStatement.executeQuery();
    720          reportSqlTiming(System.currentTimeMillis() - tstart, dumpedSql, methodCall);
    721          ResultSetSpy rsp = new ResultSetSpy(this, r);
    722          return (ResultSet) reportReturn(methodCall, rsp);
    723        }
    724        catch (SQLException s)
    725        {
    726          reportException(methodCall, s, dumpedSql, System.currentTimeMillis() - tstart);
    727          throw s;
    728        }
    729      }
    730
    731      private String getTypeHelp(Object x)
    732      {
    733        if (x==null)
    734        {
    735          return "(null)";
    736        }
    737        else
    738        {
    739          return "(" + x.getClass().getName() + ")";
    740        }
    741      }
    742
    743      public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException
    744      {
    745        String methodCall = "setObject(" + parameterIndex + ", " + x + ", " + targetSqlType + ", " + scale + ")";
    746        argTraceSet(parameterIndex, getTypeHelp(x), rdbmsSpecifics.formatParameterObject(x));
    747
    748        try
    749        {
    750          realPreparedStatement.setObject(parameterIndex, x, targetSqlType, scale);
    751        }
    752        catch (SQLException s)
    753        {
    754          reportException(methodCall, s);
    755          throw s;
    756        }
    757        reportReturn(methodCall);
    758      }
    759
    760      /**
    761       * Sets the designated parameter to the given input stream, which will have
    762       * the specified number of bytes.
    763       * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
    764       * parameter, it may be more practical to send it via a
    765       * <code>java.io.InputStream</code>. Data will be read from the stream
    766       * as needed until end-of-file is reached.  The JDBC driver will
    767       * do any necessary conversion from ASCII to the database char format.
    768       * <p/>
    769       * <P><B>Note:</B> This stream object can either be a standard
    770       * Java stream object or your own subclass that implements the
    771       * standard interface.
    772       *
    773       * @param parameterIndex the first parameter is 1, the second is 2, ...
    774       * @param x              the Java input stream that contains the ASCII parameter value
    775       * @param length         the number of bytes in the stream
    776       * @throws java.sql.SQLException if parameterIndex does not correspond to a parameter
    777       *                               marker in the SQL statement; if a database access error occurs or
    778       *                               this method is called on a closed <code>PreparedStatement</code>
    779       * @since 1.6
    780       */
    781      public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
    782        String methodCall = "setAsciiStream(" + parameterIndex + ", " + x + ", " + length + ")";
    783        argTraceSet(parameterIndex, "(Ascii InputStream)", "<Ascii InputStream of length " + length + ">");
    784        try
    785        {
    786          realPreparedStatement.setAsciiStream(parameterIndex, x, length);
    787        }
    788        catch (SQLException s)
    789        {
    790          reportException(methodCall, s);
    791          throw s;
    792        }
    793        reportReturn(methodCall);
    794      }
    795
    796      public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
    797        String methodCall = "setBinaryStream(" + parameterIndex + ", " + x + ", " + length + ")";
    798        argTraceSet(parameterIndex, "(Binary InputStream)", "<Binary InputStream of length " + length + ">");
    799        try
    800        {
    801          realPreparedStatement.setBinaryStream(parameterIndex, x, length);
    802        }
    803        catch (SQLException s)
    804        {
    805          reportException(methodCall, s);
    806          throw s;
    807        }
    808        reportReturn(methodCall);
    809      }
    810
    811      public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
    812        String methodCall = "setCharacterStream(" + parameterIndex + ", " + reader + ", " + length + ")";
    813        argTraceSet(parameterIndex, "(Reader)", "<Reader of length " + length + ">");
    814        try
    815        {
    816          realPreparedStatement.setCharacterStream(parameterIndex, reader, length);
    817        }
    818        catch (SQLException s)
    819        {
    820          reportException(methodCall, s);
    821          throw s;
    822        }
    823        reportReturn(methodCall);
    824
    825      }
    826
    827      public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
    828        String methodCall = "setAsciiStream(" + parameterIndex + ", " + x + ")";
    829        argTraceSet(parameterIndex, "(Ascii InputStream)", "<Ascii InputStream>");
    830        try
    831        {
    832          realPreparedStatement.setAsciiStream(parameterIndex, x);
    833        }
    834        catch (SQLException s)
    835        {
    836          reportException(methodCall, s);
    837          throw s;
    838        }
    839        reportReturn(methodCall);
    840      }
    841
    842      public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
    843        String methodCall = "setBinaryStream(" + parameterIndex + ", " + x + ")";
    844        argTraceSet(parameterIndex, "(Binary InputStream)", "<Binary InputStream>");
    845        try
    846        {
    847          realPreparedStatement.setBinaryStream(parameterIndex, x);
    848        }
    849        catch (SQLException s)
    850        {
    851          reportException(methodCall, s);
    852          throw s;
    853        }
    854        reportReturn(methodCall);
    855
    856      }
    857
    858      public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
    859        String methodCall = "setCharacterStream(" + parameterIndex + ", " + reader + ")";
    860        argTraceSet(parameterIndex, "(Reader)", "<Reader>");
    861        try
    862        {
    863          realPreparedStatement.setCharacterStream(parameterIndex, reader);
    864        }
    865        catch (SQLException s)
    866        {
    867          reportException(methodCall, s);
    868          throw s;
    869        }
    870        reportReturn(methodCall);
    871      }
    872
    873      public void setNCharacterStream(int parameterIndex, Reader reader) throws SQLException {
    874        String methodCall = "setNCharacterStream(" + parameterIndex + ", " + reader + ")";
    875        argTraceSet(parameterIndex, "(Reader)", "<Reader>");
    876        try
    877        {
    878          realPreparedStatement.setNCharacterStream(parameterIndex, reader);
    879        }
    880        catch (SQLException s)
    881        {
    882          reportException(methodCall, s);
    883          throw s;
    884        }
    885        reportReturn(methodCall);
    886      }
    887
    888      public void setClob(int parameterIndex, Reader reader) throws SQLException {
    889        String methodCall = "setClob(" + parameterIndex + ", " + reader + ")";
    890        argTraceSet(parameterIndex, "(Reader)", "<Reader>");
    891        try
    892        {
    893          realPreparedStatement.setClob(parameterIndex, reader);
    894        }
    895        catch (SQLException s)
    896        {
    897          reportException(methodCall, s);
    898          throw s;
    899        }
    900        reportReturn(methodCall);
    901      }
    902
    903      public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
    904        String methodCall = "setBlob(" + parameterIndex + ", " + inputStream + ")";
    905        argTraceSet(parameterIndex, "(InputStream)", "<InputStream>");
    906        try
    907        {
    908          realPreparedStatement.setBlob(parameterIndex, inputStream);
    909        }
    910        catch (SQLException s)
    911        {
    912          reportException(methodCall, s);
    913          throw s;
    914        }
    915        reportReturn(methodCall);
    916      }
    917
    918      public void setNClob(int parameterIndex, Reader reader) throws SQLException {
    919        String methodCall = "setNClob(" + parameterIndex + ", " + reader + ")";
    920        argTraceSet(parameterIndex, "(Reader)", "<Reader>");
    921        try
    922        {
    923          realPreparedStatement.setNClob(parameterIndex, reader);
    924        }
    925        catch (SQLException s)
    926        {
    927          reportException(methodCall, s);
    928          throw s;
    929        }
    930        reportReturn(methodCall);
    931
    932      }
    933
    934      public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException
    935      {
    936        String methodCall = "setObject(" + parameterIndex + ", " + x + ", " + targetSqlType + ")";
    937        argTraceSet(parameterIndex, getTypeHelp(x), rdbmsSpecifics.formatParameterObject(x));
    938        try
    939        {
    940          realPreparedStatement.setObject(parameterIndex, x, targetSqlType);
    941        }
    942        catch (SQLException s)
    943        {
    944          reportException(methodCall, s);
    945          throw s;
    946        }
    947        reportReturn(methodCall);
    948      }
    949
    950      public void setObject(int parameterIndex, Object x) throws SQLException
    951      {
    952        String methodCall = "setObject(" + parameterIndex + ", " + x + ")";
    953        argTraceSet(parameterIndex, getTypeHelp(x), rdbmsSpecifics.formatParameterObject(x));
    954        try
    955        {
    956          realPreparedStatement.setObject(parameterIndex, x);
    957        }
    958        catch (SQLException s)
    959        {
    960          reportException(methodCall, s);
    961          throw s;
    962        }
    963        reportReturn(methodCall);
    964      }
    965
    966      public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
    967      {
    968        String methodCall = "setTimestamp(" + parameterIndex + ", " + x + ")";
    969        argTraceSet(parameterIndex, "(Date)", rdbmsSpecifics.formatParameterObject(x));
    970        try
    971        {
    972          realPreparedStatement.setTimestamp(parameterIndex, x);
    973        }
    974        catch (SQLException s)
    975        {
    976          reportException(methodCall, s);
    977          throw s;
    978        }
    979        reportReturn(methodCall);
    980      }
    981
    982      public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException
    983      {
    984        String methodCall = "setTimestamp(" + parameterIndex + ", " + x + ", " + cal + ")";
    985        argTraceSet(parameterIndex, "(Timestamp)", rdbmsSpecifics.formatParameterObject(x));
    986        try
    987        {
    988          realPreparedStatement.setTimestamp(parameterIndex, x, cal);
    989        }
    990        catch (SQLException s)
    991        {
    992          reportException(methodCall, s);
    993          throw s;
    994        }
    995        reportReturn(methodCall);
    996      }
    997
    998      public int executeUpdate() throws SQLException
    999      {
    1000        String methodCall = "executeUpdate()";
    1001        String dumpedSql = dumpedSql();
    1002        reportSql(dumpedSql, methodCall);
    1003        long tstart = System.currentTimeMillis();
    1004        try
    1005        {
    1006          int result = realPreparedStatement.executeUpdate();
    1007          reportSqlTiming(System.currentTimeMillis() - tstart, dumpedSql, methodCall);
    1008          return reportReturn(methodCall, result);
    1009        }
    1010        catch (SQLException s)
    1011        {
    1012          reportException(methodCall, s, dumpedSql, System.currentTimeMillis() - tstart);
    1013          throw s;
    1014        }
    1015      }
    1016
    1017      public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
    1018      {
    1019        String methodCall = "setAsciiStream(" + parameterIndex + ", " + x + ", " + length + ")";
    1020        argTraceSet(parameterIndex, "(Ascii InputStream)", "<Ascii InputStream of length " + length + ">");
    1021        try
    1022        {
    1023          realPreparedStatement.setAsciiStream(parameterIndex, x, length);
    1024        }
    1025        catch (SQLException s)
    1026        {
    1027          reportException(methodCall, s);
    1028          throw s;
    1029        }
    1030        reportReturn(methodCall);
    1031      }
    1032
    1033      public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
    1034      {
    1035        String methodCall = "setBinaryStream(" + parameterIndex + ", " + x + ", " + length + ")";
    1036        argTraceSet(parameterIndex, "(Binary InputStream)", "<Binary InputStream of length " + length + ">");
    1037        try
    1038        {
    1039          realPreparedStatement.setBinaryStream(parameterIndex, x, length);
    1040        }
    1041        catch (SQLException s)
    1042        {
    1043          reportException(methodCall, s);
    1044          throw s;
    1045        }
    1046        reportReturn(methodCall);
    1047      }
    1048
    1049      public void clearParameters() throws SQLException
    1050      {
    1051        String methodCall = "clearParameters()";
    1052
    1053        synchronized (argTrace)
    1054        {
    1055          argTrace.clear();
    1056        }
    1057
    1058        try
    1059        {
    1060          realPreparedStatement.clearParameters();
    1061        }
    1062        catch (SQLException s)
    1063        {
    1064          reportException(methodCall, s);
    1065          throw s;
    1066        }
    1067        reportReturn(methodCall);
    1068      }
    1069
    1070      public ResultSetMetaData getMetaData() throws SQLException
    1071      {
    1072        String methodCall = "getMetaData()";
    1073        try
    1074        {
    1075          return (ResultSetMetaData) reportReturn(methodCall, realPreparedStatement.getMetaData());
    1076        }
    1077        catch (SQLException s)
    1078        {
    1079          reportException(methodCall, s);
    1080          throw s;
    1081        }
    1082      }
    1083
    1084      public void addBatch() throws SQLException
    1085      {
    1086        String methodCall = "addBatch()";
    1087        currentBatch.add(dumpedSql());
    1088        try
    1089        {
    1090          realPreparedStatement.addBatch();
    1091        }
    1092        catch (SQLException s)
    1093        {
    1094          reportException(methodCall, s);
    1095          throw s;
    1096        }
    1097        reportReturn(methodCall);
    1098      }
    1099
    1100      public <T> T unwrap(Class<T> iface) throws SQLException {
    1101        String methodCall = "unwrap(" + (iface==null?"null":iface.getName()) + ")";
    1102        try
    1103        {
    1104          //todo: double check this logic
    1105          //NOTE: could call super.isWrapperFor to simplify this logic, but it would result in extra log output
    1106          //because the super classes would be invoked, thus executing their logging methods too...
    1107          return (T)reportReturn(methodCall,
    1108            (iface != null && (iface==PreparedStatement.class||iface==Statement.class||iface==Spy.class))?
    1109              (T)this:
    1110              realPreparedStatement.unwrap(iface));
    1111        }
    1112        catch (SQLException s)
    1113        {
    1114          reportException(methodCall,s);
    1115          throw s;
    1116        }
    1117      }
    1118
    1119      public boolean isWrapperFor(Class<?> iface) throws SQLException
    1120      {
    1121        String methodCall = "isWrapperFor(" + (iface==null?"null":iface.getName()) + ")";
    1122        try
    1123        {
    1124          //NOTE: could call super.isWrapperFor to simplify this logic, but it would result in extra log output
    1125          //when the super classes would be invoked..
    1126          return reportReturn(methodCall,
    1127            (iface != null && (iface==PreparedStatement.class||iface==Statement.class||iface==Spy.class)) ||
    1128            realPreparedStatement.isWrapperFor(iface));
    1129        }
    1130        catch (SQLException s)
    1131        {
    1132          reportException(methodCall,s);
    1133          throw s;
    1134        }
    1135      }
    1136
    1137    }