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    @Override
171    public void setArray(final int i, final Array x) throws SQLException {
172        checkOpen();
173        try {
174            getDelegatePreparedStatement().setArray(i, x);
175        } catch (final SQLException e) {
176            handleException(e);
177        }
178    }
179
180    @Override
181    public void setAsciiStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
182        checkOpen();
183        try {
184            getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream);
185        } catch (final SQLException e) {
186            handleException(e);
187        }
188    }
189
190    @Override
191    public void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
192        checkOpen();
193        try {
194            getDelegatePreparedStatement().setAsciiStream(parameterIndex, x, length);
195        } catch (final SQLException e) {
196            handleException(e);
197        }
198    }
199
200    @Override
201    public void setAsciiStream(final int parameterIndex, final InputStream inputStream, final long length)
202            throws SQLException {
203        checkOpen();
204        try {
205            getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream, length);
206        } catch (final SQLException e) {
207            handleException(e);
208        }
209    }
210
211    @Override
212    public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException {
213        checkOpen();
214        try {
215            getDelegatePreparedStatement().setBigDecimal(parameterIndex, x);
216        } catch (final SQLException e) {
217            handleException(e);
218        }
219    }
220
221    @Override
222    public void setBinaryStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
223        checkOpen();
224        try {
225            getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream);
226        } catch (final SQLException e) {
227            handleException(e);
228        }
229    }
230
231    @Override
232    public void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
233        checkOpen();
234        try {
235            getDelegatePreparedStatement().setBinaryStream(parameterIndex, x, length);
236        } catch (final SQLException e) {
237            handleException(e);
238        }
239    }
240
241    @Override
242    public void setBinaryStream(final int parameterIndex, final InputStream inputStream, final long length)
243            throws SQLException {
244        checkOpen();
245        try {
246            getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream, length);
247        } catch (final SQLException e) {
248            handleException(e);
249        }
250    }
251
252    @Override
253    public void setBlob(final int i, final Blob x) throws SQLException {
254        checkOpen();
255        try {
256            getDelegatePreparedStatement().setBlob(i, x);
257        } catch (final SQLException e) {
258            handleException(e);
259        }
260    }
261
262    @Override
263    public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException {
264        checkOpen();
265        try {
266            getDelegatePreparedStatement().setBlob(parameterIndex, inputStream);
267        } catch (final SQLException e) {
268            handleException(e);
269        }
270    }
271
272    @Override
273    public void setBlob(final int parameterIndex, final InputStream inputStream, final long length)
274            throws SQLException {
275        checkOpen();
276        try {
277            getDelegatePreparedStatement().setBlob(parameterIndex, inputStream, length);
278        } catch (final SQLException e) {
279            handleException(e);
280        }
281    }
282
283    @Override
284    public void setBoolean(final int parameterIndex, final boolean x) throws SQLException {
285        checkOpen();
286        try {
287            getDelegatePreparedStatement().setBoolean(parameterIndex, x);
288        } catch (final SQLException e) {
289            handleException(e);
290        }
291    }
292
293    @Override
294    public void setByte(final int parameterIndex, final byte x) throws SQLException {
295        checkOpen();
296        try {
297            getDelegatePreparedStatement().setByte(parameterIndex, x);
298        } catch (final SQLException e) {
299            handleException(e);
300        }
301    }
302
303    @Override
304    public void setBytes(final int parameterIndex, final byte[] x) throws SQLException {
305        checkOpen();
306        try {
307            getDelegatePreparedStatement().setBytes(parameterIndex, x);
308        } catch (final SQLException e) {
309            handleException(e);
310        }
311    }
312
313    @Override
314    public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
315        checkOpen();
316        try {
317            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader);
318        } catch (final SQLException e) {
319            handleException(e);
320        }
321    }
322
323    @Override
324    public void setCharacterStream(final int parameterIndex, final Reader reader, final int length)
325            throws SQLException {
326        checkOpen();
327        try {
328            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
329        } catch (final SQLException e) {
330            handleException(e);
331        }
332    }
333
334    @Override
335    public void setCharacterStream(final int parameterIndex, final Reader reader, final long length)
336            throws SQLException {
337        checkOpen();
338        try {
339            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
340        } catch (final SQLException e) {
341            handleException(e);
342        }
343    }
344
345    @Override
346    public void setClob(final int i, final Clob x) throws SQLException {
347        checkOpen();
348        try {
349            getDelegatePreparedStatement().setClob(i, x);
350        } catch (final SQLException e) {
351            handleException(e);
352        }
353    }
354
355    @Override
356    public void setClob(final int parameterIndex, final Reader reader) throws SQLException {
357        checkOpen();
358        try {
359            getDelegatePreparedStatement().setClob(parameterIndex, reader);
360        } catch (final SQLException e) {
361            handleException(e);
362        }
363    }
364
365    @Override
366    public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
367        checkOpen();
368        try {
369            getDelegatePreparedStatement().setClob(parameterIndex, reader, length);
370        } catch (final SQLException e) {
371            handleException(e);
372        }
373    }
374
375    @Override
376    public void setDate(final int parameterIndex, final Date x) throws SQLException {
377        checkOpen();
378        try {
379            getDelegatePreparedStatement().setDate(parameterIndex, x);
380        } catch (final SQLException e) {
381            handleException(e);
382        }
383    }
384
385    @Override
386    public void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException {
387        checkOpen();
388        try {
389            getDelegatePreparedStatement().setDate(parameterIndex, x, cal);
390        } catch (final SQLException e) {
391            handleException(e);
392        }
393    }
394
395    @Override
396    public void setDouble(final int parameterIndex, final double x) throws SQLException {
397        checkOpen();
398        try {
399            getDelegatePreparedStatement().setDouble(parameterIndex, x);
400        } catch (final SQLException e) {
401            handleException(e);
402        }
403    }
404
405    @Override
406    public void setFloat(final int parameterIndex, final float x) throws SQLException {
407        checkOpen();
408        try {
409            getDelegatePreparedStatement().setFloat(parameterIndex, x);
410        } catch (final SQLException e) {
411            handleException(e);
412        }
413    }
414
415    @Override
416    public void setInt(final int parameterIndex, final int x) throws SQLException {
417        checkOpen();
418        try {
419            getDelegatePreparedStatement().setInt(parameterIndex, x);
420        } catch (final SQLException e) {
421            handleException(e);
422        }
423    }
424
425    @Override
426    public void setLong(final int parameterIndex, final long x) throws SQLException {
427        checkOpen();
428        try {
429            getDelegatePreparedStatement().setLong(parameterIndex, x);
430        } catch (final SQLException e) {
431            handleException(e);
432        }
433    }
434
435    @Override
436    public void setNCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
437        checkOpen();
438        try {
439            getDelegatePreparedStatement().setNCharacterStream(parameterIndex, reader);
440        } catch (final SQLException e) {
441            handleException(e);
442        }
443    }
444
445    @Override
446    public void setNCharacterStream(final int parameterIndex, final Reader value, final long length)
447            throws SQLException {
448        checkOpen();
449        try {
450            getDelegatePreparedStatement().setNCharacterStream(parameterIndex, value, length);
451        } catch (final SQLException e) {
452            handleException(e);
453        }
454    }
455
456    @Override
457    public void setNClob(final int parameterIndex, final NClob value) throws SQLException {
458        checkOpen();
459        try {
460            getDelegatePreparedStatement().setNClob(parameterIndex, value);
461        } catch (final SQLException e) {
462            handleException(e);
463        }
464    }
465
466    @Override
467    public void setNClob(final int parameterIndex, final Reader reader) throws SQLException {
468        checkOpen();
469        try {
470            getDelegatePreparedStatement().setNClob(parameterIndex, reader);
471        } catch (final SQLException e) {
472            handleException(e);
473        }
474    }
475
476    @Override
477    public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
478        checkOpen();
479        try {
480            getDelegatePreparedStatement().setNClob(parameterIndex, reader, length);
481        } catch (final SQLException e) {
482            handleException(e);
483        }
484    }
485
486    @Override
487    public void setNString(final int parameterIndex, final String value) throws SQLException {
488        checkOpen();
489        try {
490            getDelegatePreparedStatement().setNString(parameterIndex, value);
491        } catch (final SQLException e) {
492            handleException(e);
493        }
494    }
495
496    @Override
497    public void setNull(final int parameterIndex, final int sqlType) throws SQLException {
498        checkOpen();
499        try {
500            getDelegatePreparedStatement().setNull(parameterIndex, sqlType);
501        } catch (final SQLException e) {
502            handleException(e);
503        }
504    }
505
506    @Override
507    public void setNull(final int paramIndex, final int sqlType, final String typeName) throws SQLException {
508        checkOpen();
509        try {
510            getDelegatePreparedStatement().setNull(paramIndex, sqlType, typeName);
511        } catch (final SQLException e) {
512            handleException(e);
513        }
514    }
515
516    @Override
517    public void setObject(final int parameterIndex, final Object x) throws SQLException {
518        checkOpen();
519        try {
520            getDelegatePreparedStatement().setObject(parameterIndex, x);
521        } catch (final SQLException e) {
522            handleException(e);
523        }
524    }
525
526    @Override
527    public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException {
528        checkOpen();
529        try {
530            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType);
531        } catch (final SQLException e) {
532            handleException(e);
533        }
534    }
535
536    @Override
537    public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale)
538            throws SQLException {
539        checkOpen();
540        try {
541            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scale);
542        } catch (final SQLException e) {
543            handleException(e);
544        }
545    }
546
547    /**
548     * @since 2.5.0
549     */
550    @Override
551    public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType) throws SQLException {
552        checkOpen();
553        try {
554            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType);
555        } catch (final SQLException e) {
556            handleException(e);
557        }
558    }
559
560    /**
561     * @since 2.5.0
562     */
563    @Override
564    public void setObject(final int parameterIndex, final Object x, final SQLType targetSqlType, final int scaleOrLength) throws SQLException {
565        checkOpen();
566        try {
567            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scaleOrLength);
568        } catch (final SQLException e) {
569            handleException(e);
570        }
571    }
572
573    @Override
574    public void setRef(final int i, final Ref x) throws SQLException {
575        checkOpen();
576        try {
577            getDelegatePreparedStatement().setRef(i, x);
578        } catch (final SQLException e) {
579            handleException(e);
580        }
581    }
582
583    @Override
584    public void setRowId(final int parameterIndex, final RowId value) throws SQLException {
585        checkOpen();
586        try {
587            getDelegatePreparedStatement().setRowId(parameterIndex, value);
588        } catch (final SQLException e) {
589            handleException(e);
590        }
591    }
592
593    @Override
594    public void setShort(final int parameterIndex, final short x) throws SQLException {
595        checkOpen();
596        try {
597            getDelegatePreparedStatement().setShort(parameterIndex, x);
598        } catch (final SQLException e) {
599            handleException(e);
600        }
601    }
602
603    @Override
604    public void setSQLXML(final int parameterIndex, final SQLXML value) throws SQLException {
605        checkOpen();
606        try {
607            getDelegatePreparedStatement().setSQLXML(parameterIndex, value);
608        } catch (final SQLException e) {
609            handleException(e);
610        }
611    }
612
613    @Override
614    public void setString(final int parameterIndex, final String x) throws SQLException {
615        checkOpen();
616        try {
617            getDelegatePreparedStatement().setString(parameterIndex, x);
618        } catch (final SQLException e) {
619            handleException(e);
620        }
621    }
622
623    @Override
624    public void setTime(final int parameterIndex, final Time x) throws SQLException {
625        checkOpen();
626        try {
627            getDelegatePreparedStatement().setTime(parameterIndex, x);
628        } catch (final SQLException e) {
629            handleException(e);
630        }
631    }
632
633    @Override
634    public void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException {
635        checkOpen();
636        try {
637            getDelegatePreparedStatement().setTime(parameterIndex, x, cal);
638        } catch (final SQLException e) {
639            handleException(e);
640        }
641    }
642
643    @Override
644    public void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException {
645        checkOpen();
646        try {
647            getDelegatePreparedStatement().setTimestamp(parameterIndex, x);
648        } catch (final SQLException e) {
649            handleException(e);
650        }
651    }
652
653    @Override
654    public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException {
655        checkOpen();
656        try {
657            getDelegatePreparedStatement().setTimestamp(parameterIndex, x, cal);
658        } catch (final SQLException e) {
659            handleException(e);
660        }
661    }
662
663    /** @deprecated Use setAsciiStream(), setCharacterStream() or setNCharacterStream() */
664    @Deprecated
665    @Override
666    public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
667        checkOpen();
668        try {
669            getDelegatePreparedStatement().setUnicodeStream(parameterIndex, x, length);
670        } catch (final SQLException e) {
671            handleException(e);
672        }
673    }
674
675    @Override
676    public void setURL(final int parameterIndex, final java.net.URL x) throws SQLException {
677        checkOpen();
678        try {
679            getDelegatePreparedStatement().setURL(parameterIndex, x);
680        } catch (final SQLException e) {
681            handleException(e);
682        }
683    }
684
685    /**
686     * Returns a String representation of this object.
687     *
688     * @return String
689     */
690    @SuppressWarnings("resource")
691    @Override
692    public synchronized String toString() {
693        final Statement statement = getDelegate();
694        return statement == null ? "NULL" : statement.toString();
695    }
696
697    protected void prepareToReturn() throws SQLException {
698        setClosedInternal(true);
699        removeThisTrace(getConnectionInternal());
700
701        // The JDBC spec requires that a statement close any open
702        // ResultSet's when it is closed.
703        // FIXME The PreparedStatement we're wrapping should handle this for us.
704        // See DBCP-10 for what could happen when ResultSets are closed twice.
705        final List<AbandonedTrace> traceList = getTrace();
706        if (traceList != null) {
707            final List<Exception> thrownList = new ArrayList<>();
708            traceList.forEach(trace -> trace.close(thrownList::add));
709            clearTrace();
710            if (!thrownList.isEmpty()) {
711                throw new SQLExceptionList(thrownList);
712            }
713        }
714
715        super.passivate();
716    }
717}