001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.dbcp2;
018
019import java.io.InputStream;
020import java.io.Reader;
021import java.math.BigDecimal;
022import java.sql.Array;
023import java.sql.Blob;
024import java.sql.Clob;
025import java.sql.Date;
026import java.sql.NClob;
027import java.sql.PreparedStatement;
028import java.sql.Ref;
029import java.sql.ResultSet;
030import java.sql.ResultSetMetaData;
031import java.sql.RowId;
032import java.sql.SQLException;
033import java.sql.SQLType;
034import java.sql.SQLXML;
035import java.sql.Statement;
036import java.sql.Time;
037import java.sql.Timestamp;
038import java.util.ArrayList;
039import java.util.Calendar;
040import java.util.List;
041
042/**
043 * A base delegating implementation of {@link PreparedStatement}.
044 * <p>
045 * All of the methods from the {@link PreparedStatement} interface simply check to see that the
046 * {@link PreparedStatement} is active, and call the corresponding method on the "delegate" provided in my constructor.
047 * <p>
048 * Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the
049 * Statement ensures that the Connection which created it can close any open Statement's on Connection close.
050 *
051 * @since 2.0
052 */
053public class DelegatingPreparedStatement extends DelegatingStatement implements PreparedStatement {
054
055    /**
056     * Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code
057     * which created it.
058     *
059     * @param statement
060     *            the {@link PreparedStatement} to delegate all calls to.
061     * @param connection
062     *            the {@link DelegatingConnection} that created this statement.
063     */
064    public DelegatingPreparedStatement(final DelegatingConnection<?> connection, final PreparedStatement statement) {
065        super(connection, statement);
066    }
067
068    @Override
069    public void addBatch() throws SQLException {
070        checkOpen();
071        try {
072            getDelegatePreparedStatement().addBatch();
073        } catch (final SQLException e) {
074            handleException(e);
075        }
076    }
077
078    @Override
079    public void clearParameters() throws SQLException {
080        checkOpen();
081        try {
082            getDelegatePreparedStatement().clearParameters();
083        } catch (final SQLException e) {
084            handleException(e);
085        }
086    }
087
088    @Override
089    public boolean execute() throws SQLException {
090        checkOpen();
091        if (getConnectionInternal() != null) {
092            getConnectionInternal().setLastUsed();
093        }
094        try {
095            return getDelegatePreparedStatement().execute();
096        } catch (final SQLException e) {
097            handleException(e);
098            return false;
099        }
100    }
101
102    /**
103     * @since 2.5.0
104     */
105    @Override
106    public long executeLargeUpdate() throws SQLException {
107        checkOpen();
108        try {
109            return getDelegatePreparedStatement().executeLargeUpdate();
110        } catch (final SQLException e) {
111            handleException(e);
112            return 0;
113        }
114    }
115
116    @Override
117    public ResultSet executeQuery() throws SQLException {
118        checkOpen();
119        if (getConnectionInternal() != null) {
120            getConnectionInternal().setLastUsed();
121        }
122        try {
123            return DelegatingResultSet.wrapResultSet(this, getDelegatePreparedStatement().executeQuery());
124        } catch (final SQLException e) {
125            handleException(e);
126            throw new AssertionError();
127        }
128    }
129
130    @Override
131    public int executeUpdate() throws SQLException {
132        checkOpen();
133        if (getConnectionInternal() != null) {
134            getConnectionInternal().setLastUsed();
135        }
136        try {
137            return getDelegatePreparedStatement().executeUpdate();
138        } catch (final SQLException e) {
139            handleException(e);
140            return 0;
141        }
142    }
143
144    private PreparedStatement getDelegatePreparedStatement() {
145        return (PreparedStatement) getDelegate();
146    }
147
148    @Override
149    public ResultSetMetaData getMetaData() throws SQLException {
150        checkOpen();
151        try {
152            return getDelegatePreparedStatement().getMetaData();
153        } catch (final SQLException e) {
154            handleException(e);
155            throw new AssertionError();
156        }
157    }
158
159    @Override
160    public java.sql.ParameterMetaData getParameterMetaData() throws SQLException {
161        checkOpen();
162        try {
163            return getDelegatePreparedStatement().getParameterMetaData();
164        } catch (final SQLException e) {
165            handleException(e);
166            throw new AssertionError();
167        }
168    }
169
170    protected void prepareToReturn() throws SQLException {
171        setClosedInternal(true);
172        removeThisTrace(getConnectionInternal());
173
174        // The JDBC spec requires that a statement close any open
175        // ResultSet's when it is closed.
176        // FIXME The PreparedStatement we're wrapping should handle this for us.
177        // See DBCP-10 for what could happen when ResultSets are closed twice.
178        final List<AbandonedTrace> traceList = getTrace();
179        if (traceList != null) {
180            final List<Exception> thrownList = new ArrayList<>();
181            traceList.forEach(trace -> trace.close(thrownList::add));
182            clearTrace();
183            if (!thrownList.isEmpty()) {
184                throw new SQLExceptionList(thrownList);
185            }
186        }
187
188        super.passivate();
189    }
190
191    @Override
192    public void setArray(final int i, final Array x) throws SQLException {
193        checkOpen();
194        try {
195            getDelegatePreparedStatement().setArray(i, x);
196        } catch (final SQLException e) {
197            handleException(e);
198        }
199    }
200
201    @Override
202    public void setAsciiStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
203        checkOpen();
204        try {
205            getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream);
206        } catch (final SQLException e) {
207            handleException(e);
208        }
209    }
210
211    @Override
212    public void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
213        checkOpen();
214        try {
215            getDelegatePreparedStatement().setAsciiStream(parameterIndex, x, length);
216        } catch (final SQLException e) {
217            handleException(e);
218        }
219    }
220
221    @Override
222    public void setAsciiStream(final int parameterIndex, final InputStream inputStream, final long length)
223            throws SQLException {
224        checkOpen();
225        try {
226            getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream, length);
227        } catch (final SQLException e) {
228            handleException(e);
229        }
230    }
231
232    @Override
233    public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException {
234        checkOpen();
235        try {
236            getDelegatePreparedStatement().setBigDecimal(parameterIndex, x);
237        } catch (final SQLException e) {
238            handleException(e);
239        }
240    }
241
242    @Override
243    public void setBinaryStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
244        checkOpen();
245        try {
246            getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream);
247        } catch (final SQLException e) {
248            handleException(e);
249        }
250    }
251
252    @Override
253    public void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
254        checkOpen();
255        try {
256            getDelegatePreparedStatement().setBinaryStream(parameterIndex, x, length);
257        } catch (final SQLException e) {
258            handleException(e);
259        }
260    }
261
262    @Override
263    public void setBinaryStream(final int parameterIndex, final InputStream inputStream, final long length)
264            throws SQLException {
265        checkOpen();
266        try {
267            getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream, length);
268        } catch (final SQLException e) {
269            handleException(e);
270        }
271    }
272
273    @Override
274    public void setBlob(final int i, final Blob x) throws SQLException {
275        checkOpen();
276        try {
277            getDelegatePreparedStatement().setBlob(i, x);
278        } catch (final SQLException e) {
279            handleException(e);
280        }
281    }
282
283    @Override
284    public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException {
285        checkOpen();
286        try {
287            getDelegatePreparedStatement().setBlob(parameterIndex, inputStream);
288        } catch (final SQLException e) {
289            handleException(e);
290        }
291    }
292
293    @Override
294    public void setBlob(final int parameterIndex, final InputStream inputStream, final long length)
295            throws SQLException {
296        checkOpen();
297        try {
298            getDelegatePreparedStatement().setBlob(parameterIndex, inputStream, length);
299        } catch (final SQLException e) {
300            handleException(e);
301        }
302    }
303
304    @Override
305    public void setBoolean(final int parameterIndex, final boolean x) throws SQLException {
306        checkOpen();
307        try {
308            getDelegatePreparedStatement().setBoolean(parameterIndex, x);
309        } catch (final SQLException e) {
310            handleException(e);
311        }
312    }
313
314    @Override
315    public void setByte(final int parameterIndex, final byte x) throws SQLException {
316        checkOpen();
317        try {
318            getDelegatePreparedStatement().setByte(parameterIndex, x);
319        } catch (final SQLException e) {
320            handleException(e);
321        }
322    }
323
324    @Override
325    public void setBytes(final int parameterIndex, final byte[] x) throws SQLException {
326        checkOpen();
327        try {
328            getDelegatePreparedStatement().setBytes(parameterIndex, x);
329        } catch (final SQLException e) {
330            handleException(e);
331        }
332    }
333
334    @Override
335    public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
336        checkOpen();
337        try {
338            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader);
339        } catch (final SQLException e) {
340            handleException(e);
341        }
342    }
343
344    @Override
345    public void setCharacterStream(final int parameterIndex, final Reader reader, final int length)
346            throws SQLException {
347        checkOpen();
348        try {
349            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
350        } catch (final SQLException e) {
351            handleException(e);
352        }
353    }
354
355    @Override
356    public void setCharacterStream(final int parameterIndex, final Reader reader, final long length)
357            throws SQLException {
358        checkOpen();
359        try {
360            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
361        } catch (final SQLException e) {
362            handleException(e);
363        }
364    }
365
366    @Override
367    public void setClob(final int i, final Clob x) throws SQLException {
368        checkOpen();
369        try {
370            getDelegatePreparedStatement().setClob(i, x);
371        } catch (final SQLException e) {
372            handleException(e);
373        }
374    }
375
376    @Override
377    public void setClob(final int parameterIndex, final Reader reader) throws SQLException {
378        checkOpen();
379        try {
380            getDelegatePreparedStatement().setClob(parameterIndex, reader);
381        } catch (final SQLException e) {
382            handleException(e);
383        }
384    }
385
386    @Override
387    public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
388        checkOpen();
389        try {
390            getDelegatePreparedStatement().setClob(parameterIndex, reader, length);
391        } catch (final SQLException e) {
392            handleException(e);
393        }
394    }
395
396    @Override
397    public void setDate(final int parameterIndex, final Date x) throws SQLException {
398        checkOpen();
399        try {
400            getDelegatePreparedStatement().setDate(parameterIndex, x);
401        } catch (final SQLException e) {
402            handleException(e);
403        }
404    }
405
406    @Override
407    public void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException {
408        checkOpen();
409        try {
410            getDelegatePreparedStatement().setDate(parameterIndex, x, cal);
411        } catch (final SQLException e) {
412            handleException(e);
413        }
414    }
415
416    @Override
417    public void setDouble(final int parameterIndex, final double x) throws SQLException {
418        checkOpen();
419        try {
420            getDelegatePreparedStatement().setDouble(parameterIndex, x);
421        } catch (final SQLException e) {
422            handleException(e);
423        }
424    }
425
426    @Override
427    public void setFloat(final int parameterIndex, final float x) throws SQLException {
428        checkOpen();
429        try {
430            getDelegatePreparedStatement().setFloat(parameterIndex, x);
431        } catch (final SQLException e) {
432            handleException(e);
433        }
434    }
435
436    @Override
437    public void setInt(final int parameterIndex, final int x) throws SQLException {
438        checkOpen();
439        try {
440            getDelegatePreparedStatement().setInt(parameterIndex, x);
441        } catch (final SQLException e) {
442            handleException(e);
443        }
444    }
445
446    @Override
447    public void setLong(final int parameterIndex, final long x) throws SQLException {
448        checkOpen();
449        try {
450            getDelegatePreparedStatement().setLong(parameterIndex, x);
451        } catch (final SQLException e) {
452            handleException(e);
453        }
454    }
455
456    @Override
457    public void setNCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
458        checkOpen();
459        try {
460            getDelegatePreparedStatement().setNCharacterStream(parameterIndex, reader);
461        } catch (final SQLException e) {
462            handleException(e);
463        }
464    }
465
466    @Override
467    public void setNCharacterStream(final int parameterIndex, final Reader value, final long length)
468            throws SQLException {
469        checkOpen();
470        try {
471            getDelegatePreparedStatement().setNCharacterStream(parameterIndex, value, length);
472        } catch (final SQLException e) {
473            handleException(e);
474        }
475    }
476
477    @Override
478    public void setNClob(final int parameterIndex, final NClob value) throws SQLException {
479        checkOpen();
480        try {
481            getDelegatePreparedStatement().setNClob(parameterIndex, value);
482        } catch (final SQLException e) {
483            handleException(e);
484        }
485    }
486
487    @Override
488    public void setNClob(final int parameterIndex, final Reader reader) throws SQLException {
489        checkOpen();
490        try {
491            getDelegatePreparedStatement().setNClob(parameterIndex, reader);
492        } catch (final SQLException e) {
493            handleException(e);
494        }
495    }
496
497    @Override
498    public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
499        checkOpen();
500        try {
501            getDelegatePreparedStatement().setNClob(parameterIndex, reader, length);
502        } catch (final SQLException e) {
503            handleException(e);
504        }
505    }
506
507    @Override
508    public void setNString(final int parameterIndex, final String value) throws SQLException {
509        checkOpen();
510        try {
511            getDelegatePreparedStatement().setNString(parameterIndex, value);
512        } catch (final SQLException e) {
513            handleException(e);
514        }
515    }
516
517    @Override
518    public void setNull(final int parameterIndex, final int sqlType) throws SQLException {
519        checkOpen();
520        try {
521            getDelegatePreparedStatement().setNull(parameterIndex, sqlType);
522        } catch (final SQLException e) {
523            handleException(e);
524        }
525    }
526
527    @Override
528    public void setNull(final int paramIndex, final int sqlType, final String typeName) throws SQLException {
529        checkOpen();
530        try {
531            getDelegatePreparedStatement().setNull(paramIndex, sqlType, typeName);
532        } catch (final SQLException e) {
533            handleException(e);
534        }
535    }
536
537    @Override
538    public void setObject(final int parameterIndex, final Object x) throws SQLException {
539        checkOpen();
540        try {
541            getDelegatePreparedStatement().setObject(parameterIndex, x);
542        } catch (final SQLException e) {
543            handleException(e);
544        }
545    }
546
547    @Override
548    public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException {
549        checkOpen();
550        try {
551            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType);
552        } catch (final SQLException e) {
553            handleException(e);
554        }
555    }
556
557    @Override
558    public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale)
559            throws SQLException {
560        checkOpen();
561        try {
562            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scale);
563        } catch (final SQLException e) {
564            handleException(e);
565        }
566    }
567
568    /**
569     * @since 2.5.0
570     */
571    @Override
572    public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType) throws SQLException {
573        checkOpen();
574        try {
575            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType);
576        } catch (final SQLException e) {
577            handleException(e);
578        }
579    }
580
581    /**
582     * @since 2.5.0
583     */
584    @Override
585    public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException {
586        checkOpen();
587        try {
588            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scaleOrLength);
589        } catch (final SQLException e) {
590            handleException(e);
591        }
592    }
593
594    @Override
595    public void setRef(final int i, final Ref x) throws SQLException {
596        checkOpen();
597        try {
598            getDelegatePreparedStatement().setRef(i, x);
599        } catch (final SQLException e) {
600            handleException(e);
601        }
602    }
603
604    @Override
605    public void setRowId(final int parameterIndex, final RowId value) throws SQLException {
606        checkOpen();
607        try {
608            getDelegatePreparedStatement().setRowId(parameterIndex, value);
609        } catch (final SQLException e) {
610            handleException(e);
611        }
612    }
613
614    @Override
615    public void setShort(final int parameterIndex, final short x) throws SQLException {
616        checkOpen();
617        try {
618            getDelegatePreparedStatement().setShort(parameterIndex, x);
619        } catch (final SQLException e) {
620            handleException(e);
621        }
622    }
623
624    @Override
625    public void setSQLXML(final int parameterIndex, final SQLXML value) throws SQLException {
626        checkOpen();
627        try {
628            getDelegatePreparedStatement().setSQLXML(parameterIndex, value);
629        } catch (final SQLException e) {
630            handleException(e);
631        }
632    }
633
634    @Override
635    public void setString(final int parameterIndex, final String x) throws SQLException {
636        checkOpen();
637        try {
638            getDelegatePreparedStatement().setString(parameterIndex, x);
639        } catch (final SQLException e) {
640            handleException(e);
641        }
642    }
643
644    @Override
645    public void setTime(final int parameterIndex, final Time x) throws SQLException {
646        checkOpen();
647        try {
648            getDelegatePreparedStatement().setTime(parameterIndex, x);
649        } catch (final SQLException e) {
650            handleException(e);
651        }
652    }
653
654    @Override
655    public void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException {
656        checkOpen();
657        try {
658            getDelegatePreparedStatement().setTime(parameterIndex, x, cal);
659        } catch (final SQLException e) {
660            handleException(e);
661        }
662    }
663
664    @Override
665    public void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException {
666        checkOpen();
667        try {
668            getDelegatePreparedStatement().setTimestamp(parameterIndex, x);
669        } catch (final SQLException e) {
670            handleException(e);
671        }
672    }
673
674    @Override
675    public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException {
676        checkOpen();
677        try {
678            getDelegatePreparedStatement().setTimestamp(parameterIndex, x, cal);
679        } catch (final SQLException e) {
680            handleException(e);
681        }
682    }
683
684    /** @deprecated Use setAsciiStream(), setCharacterStream() or setNCharacterStream() */
685    @Deprecated
686    @Override
687    public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
688        checkOpen();
689        try {
690            getDelegatePreparedStatement().setUnicodeStream(parameterIndex, x, length);
691        } catch (final SQLException e) {
692            handleException(e);
693        }
694    }
695
696    @Override
697    public void setURL(final int parameterIndex, final java.net.URL x) throws SQLException {
698        checkOpen();
699        try {
700            getDelegatePreparedStatement().setURL(parameterIndex, x);
701        } catch (final SQLException e) {
702            handleException(e);
703        }
704    }
705
706    /**
707     * Returns a String representation of this object.
708     *
709     * @return String
710     */
711    @SuppressWarnings("resource")
712    @Override
713    public synchronized String toString() {
714        final Statement statement = getDelegate();
715        return statement == null ? "NULL" : statement.toString();
716    }
717}