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 *      https://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.sql.Connection;
020import java.sql.ResultSet;
021import java.sql.SQLException;
022import java.sql.Statement;
023import java.util.Arrays;
024import java.util.Objects;
025import java.util.function.Function;
026
027import org.apache.commons.dbcp2.PoolingConnection.StatementType;
028
029/**
030 * A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s.
031 *
032 * @since 2.0
033 */
034public class PStmtKey {
035
036    /**
037     * Interface for Prepared or Callable Statement.
038     */
039    @FunctionalInterface
040    private interface StatementBuilder {
041        Statement createStatement(Connection connection, PStmtKey key) throws SQLException;
042    }
043
044    private static final StatementBuilder CallConcurrency = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency);
045    private static final StatementBuilder CallHoldability = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency, k.resultSetHoldability);
046    private static final StatementBuilder CallSQL = (c, k) -> c.prepareCall(k.sql);
047    private static final StatementBuilder StatementAutoGeneratedKeys = (c, k) -> c.prepareStatement(k.sql, k.autoGeneratedKeys);
048    private static final StatementBuilder StatementColumnIndexes = (c, k) -> c.prepareStatement(k.sql, k.columnIndexes);
049    private static final StatementBuilder StatementColumnNames = (c, k) -> c.prepareStatement(k.sql, k.columnNames);
050    private static final StatementBuilder StatementConcurrency = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency);
051    private static final StatementBuilder StatementHoldability = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency,
052        k.resultSetHoldability);
053    private static final StatementBuilder StatementSQL = (c, k) -> c.prepareStatement(k.sql);
054
055    private static StatementBuilder match(final StatementType statementType, final StatementBuilder prep, final StatementBuilder call) {
056        switch (Objects.requireNonNull(statementType, "statementType")) {
057        case PREPARED_STATEMENT:
058            return prep;
059        case CALLABLE_STATEMENT:
060            return call;
061        default:
062            throw new IllegalArgumentException(statementType.toString());
063        }
064    }
065
066    /**
067     * SQL defining Prepared or Callable Statement
068     */
069    private final String sql;
070
071    /**
072     * Result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY}, {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or
073     * {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
074     */
075    private final Integer resultSetType;
076
077    /**
078     * Result set concurrency. A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
079     * {@link ResultSet#CONCUR_UPDATABLE}.
080     */
081    private final Integer resultSetConcurrency;
082
083    /**
084     * Result set holdability. One of the following {@link ResultSet} constants: {@link ResultSet#HOLD_CURSORS_OVER_COMMIT}
085     * or {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}.
086     */
087    private final Integer resultSetHoldability;
088
089    /**
090     * Database catalog.
091     */
092    private final String catalog;
093
094    /**
095     * Database schema.
096     */
097    private final String schema;
098
099    /**
100     * A flag indicating whether auto-generated keys should be returned; one of {@link Statement#RETURN_GENERATED_KEYS} or
101     * {@link Statement#NO_GENERATED_KEYS}.
102     */
103    private final Integer autoGeneratedKeys;
104
105    /**
106     * An array of column indexes indicating the columns that should be returned from the inserted row or rows.
107     */
108    private final int[] columnIndexes;
109
110    /**
111     * An array of column names indicating the columns that should be returned from the inserted row or rows.
112     */
113    private final String[] columnNames;
114
115    /**
116     * Statement builder.
117     */
118    private final transient StatementBuilder statementBuilder;
119
120    /**
121     * Statement type, prepared or callable.
122     */
123    private final StatementType statementType;
124
125    /**
126     * Constructs a key to uniquely identify a prepared statement.
127     *
128     * @param sql The SQL statement.
129     * @deprecated Use {@link #PStmtKey(String, String, String)}.
130     */
131    @Deprecated
132    public PStmtKey(final String sql) {
133        this(sql, null, StatementType.PREPARED_STATEMENT);
134    }
135
136    /**
137     * Constructs a key to uniquely identify a prepared statement.
138     *
139     * @param sql The SQL statement.
140     * @param resultSetType A result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
141     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
142     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
143     *        {@link ResultSet#CONCUR_UPDATABLE}.
144     * @deprecated Use {@link #PStmtKey(String, String, String, int, int)}.
145     */
146    @Deprecated
147    public PStmtKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
148        this(sql, null, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
149    }
150
151    /**
152     * Constructs a key to uniquely identify a prepared statement.
153     *
154     * @param sql The SQL statement.
155     * @param catalog The catalog.
156     * @deprecated Use {@link #PStmtKey(String, String, String)}.
157     */
158    @Deprecated
159    public PStmtKey(final String sql, final String catalog) {
160        this(sql, catalog, StatementType.PREPARED_STATEMENT);
161    }
162
163    /**
164     * Constructs a key to uniquely identify a prepared statement.
165     *
166     * @param sql The SQL statement.
167     * @param catalog The catalog.
168     * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
169     *        {@link Statement#RETURN_GENERATED_KEYS} or {@link Statement#NO_GENERATED_KEYS}.
170     * @deprecated Use {@link #PStmtKey(String, String, String, int)}.
171     */
172    @Deprecated
173    public PStmtKey(final String sql, final String catalog, final int autoGeneratedKeys) {
174        this(sql, catalog, StatementType.PREPARED_STATEMENT, autoGeneratedKeys);
175    }
176
177    /**
178     * Constructs a key to uniquely identify a prepared statement.
179     *
180     * @param sql The SQL statement.
181     * @param catalog The catalog.
182     * @param resultSetType A result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
183     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
184     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
185     *        {@link ResultSet#CONCUR_UPDATABLE}.
186     * @deprecated Use {@link #PStmtKey(String, String, String, int, int)}.
187     */
188    @Deprecated
189    public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency) {
190        this(sql, catalog, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
191    }
192
193    /**
194     * Constructs a key to uniquely identify a prepared statement.
195     *
196     * @param sql The SQL statement.
197     * @param catalog The catalog.
198     * @param resultSetType a result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
199     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
200     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
201     *        {@link ResultSet#CONCUR_UPDATABLE}
202     * @param resultSetHoldability One of the following {@link ResultSet} constants:
203     *        {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} or {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}.
204     * @deprecated Use {@link #PStmtKey(String, String, String, int, int, int)}.
205     */
206    @Deprecated
207    public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) {
208        this(sql, catalog, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT);
209    }
210
211    /**
212     * Constructs a key to uniquely identify a prepared statement.
213     *
214     * @param sql The SQL statement.
215     * @param catalog The catalog.
216     * @param resultSetType a result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
217     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}
218     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
219     *        {@link ResultSet#CONCUR_UPDATABLE}.
220     * @param resultSetHoldability One of the following {@link ResultSet} constants:
221     *        {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} or {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}.
222     * @param statementType The SQL statement type, prepared or callable.
223     * @deprecated Use {@link #PStmtKey(String, String, String, int, int, int, PoolingConnection.StatementType)}
224     */
225    @Deprecated
226    public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability,
227        final StatementType statementType) {
228        this(sql, catalog, null, resultSetType, resultSetConcurrency, resultSetHoldability, null, null, null, statementType,
229            k -> match(statementType, StatementHoldability, CallHoldability));
230    }
231
232    /**
233     * Constructs a key to uniquely identify a prepared statement.
234     *
235     * @param sql The SQL statement.
236     * @param catalog The catalog.
237     * @param resultSetType A result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
238     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
239     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
240     *        {@link ResultSet#CONCUR_UPDATABLE}.
241     * @param statementType The SQL statement type, prepared or callable.
242     * @deprecated Use {@link #PStmtKey(String, String, String, int, int, PoolingConnection.StatementType)}.
243     */
244    @Deprecated
245    public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final StatementType statementType) {
246        this(sql, catalog, null, resultSetType, resultSetConcurrency, null, null, null, null, statementType,
247            k -> match(statementType, StatementConcurrency, CallConcurrency));
248    }
249
250    /**
251     * Constructs a key to uniquely identify a prepared statement.
252     *
253     * @param sql The SQL statement.
254     * @param catalog The catalog.
255     * @param columnIndexes An array of column indexes indicating the columns that should be returned from the inserted row
256     *        or rows.
257     * @deprecated Use {@link #PStmtKey(String, String, String, int[])}.
258     */
259    @Deprecated
260    public PStmtKey(final String sql, final String catalog, final int[] columnIndexes) {
261        this(sql, catalog, null, null, null, null, null, columnIndexes, null, StatementType.PREPARED_STATEMENT, StatementColumnIndexes);
262    }
263
264    /**
265     * Constructs a key to uniquely identify a prepared statement.
266     *
267     * @param sql The SQL statement.
268     * @param catalog The catalog.
269     * @param statementType The SQL statement type, prepared or callable.
270     * @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType)}.
271     */
272    @Deprecated
273    public PStmtKey(final String sql, final String catalog, final StatementType statementType) {
274        this(sql, catalog, null, null, null, null, null, null, null, statementType, k -> match(statementType, StatementSQL, CallSQL));
275    }
276
277    /**
278     * Constructs a key to uniquely identify a prepared statement.
279     *
280     * @param sql The SQL statement.
281     * @param catalog The catalog.
282     * @param statementType The SQL statement type, prepared or callable.
283     * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
284     *        {@link Statement#RETURN_GENERATED_KEYS} or {@link Statement#NO_GENERATED_KEYS}.
285     * @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType, Integer)}
286     */
287    @Deprecated
288    public PStmtKey(final String sql, final String catalog, final StatementType statementType, final Integer autoGeneratedKeys) {
289        this(sql, catalog, null, null, null, null, autoGeneratedKeys, null, null, statementType,
290            k -> match(statementType, StatementAutoGeneratedKeys, CallSQL));
291    }
292
293    /**
294     * Constructs a key to uniquely identify a prepared statement.
295     *
296     * @param sql The SQL statement.
297     * @param catalog The catalog.
298     * @param schema The schema
299     * @since 2.5.0
300     */
301    public PStmtKey(final String sql, final String catalog, final String schema) {
302        this(sql, catalog, schema, StatementType.PREPARED_STATEMENT);
303    }
304
305    /**
306     * Constructs a key to uniquely identify a prepared statement.
307     *
308     * @param sql The SQL statement.
309     * @param catalog The catalog.
310     * @param schema The schema
311     * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
312     *        {@link Statement#RETURN_GENERATED_KEYS} or {@link Statement#NO_GENERATED_KEYS}.
313     * @since 2.5.0
314     */
315    public PStmtKey(final String sql, final String catalog, final String schema, final int autoGeneratedKeys) {
316        this(sql, catalog, schema, StatementType.PREPARED_STATEMENT, autoGeneratedKeys);
317    }
318
319    /**
320     * Constructs a key to uniquely identify a prepared statement.
321     *
322     * @param sql The SQL statement.
323     * @param catalog The catalog.
324     * @param schema The schema
325     * @param resultSetType A result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
326     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
327     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
328     *        {@link ResultSet#CONCUR_UPDATABLE}.
329     */
330    public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency) {
331        this(sql, catalog, schema, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
332    }
333
334    /**
335     * Constructs a key to uniquely identify a prepared statement.
336     *
337     * @param sql The SQL statement.
338     * @param catalog The catalog.
339     * @param schema The schema
340     * @param resultSetType a result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
341     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
342     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
343     *        {@link ResultSet#CONCUR_UPDATABLE}
344     * @param resultSetHoldability One of the following {@link ResultSet} constants:
345     *        {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} or {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}.
346     * @since 2.5.0
347     */
348    public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
349        final int resultSetHoldability) {
350        this(sql, catalog, schema, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT);
351    }
352
353    /**
354     * Constructs a key to uniquely identify a prepared statement.
355     *
356     * @param sql The SQL statement.
357     * @param catalog The catalog.
358     * @param schema The schema.
359     * @param resultSetType a result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
360     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}
361     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
362     *        {@link ResultSet#CONCUR_UPDATABLE}.
363     * @param resultSetHoldability One of the following {@link ResultSet} constants:
364     *        {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} or {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}.
365     * @param statementType The SQL statement type, prepared or callable.
366     * @since 2.5.0
367     */
368    public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
369        final int resultSetHoldability, final StatementType statementType) {
370        this(sql, catalog, schema, resultSetType, resultSetConcurrency, resultSetHoldability, null, null, null, statementType,
371            k -> match(statementType, StatementHoldability, CallHoldability));
372    }
373
374    /**
375     * Constructs a key to uniquely identify a prepared statement.
376     *
377     * @param sql The SQL statement.
378     * @param catalog The catalog.
379     * @param schema The schema.
380     * @param resultSetType A result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY},
381     *        {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
382     * @param resultSetConcurrency A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
383     *        {@link ResultSet#CONCUR_UPDATABLE}.
384     * @param statementType The SQL statement type, prepared or callable.
385     * @since 2.5.0
386     */
387    public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
388        final StatementType statementType) {
389        this(sql, catalog, schema, resultSetType, resultSetConcurrency, null, null, null, null, statementType,
390            k -> match(statementType, StatementConcurrency, CallConcurrency));
391    }
392
393    /**
394     * Constructs a key to uniquely identify a prepared statement.
395     *
396     * @param sql The SQL statement.
397     * @param catalog The catalog.
398     * @param schema The schema.
399     * @param columnIndexes An array of column indexes indicating the columns that should be returned from the inserted row
400     *        or rows.
401     */
402    public PStmtKey(final String sql, final String catalog, final String schema, final int[] columnIndexes) {
403        this(sql, catalog, schema, null, null, null, null, columnIndexes, null, StatementType.PREPARED_STATEMENT, StatementColumnIndexes);
404    }
405
406    private PStmtKey(final String sql, final String catalog, final String schema, final Integer resultSetType, final Integer resultSetConcurrency,
407        final Integer resultSetHoldability, final Integer autoGeneratedKeys, final int[] columnIndexes, final String[] columnNames,
408        final StatementType statementType, final Function<PStmtKey, StatementBuilder> statementBuilder) {
409        this.sql = Objects.requireNonNull(sql, "sql").trim();
410        this.catalog = catalog;
411        this.schema = schema;
412        this.resultSetType = resultSetType;
413        this.resultSetConcurrency = resultSetConcurrency;
414        this.resultSetHoldability = resultSetHoldability;
415        this.autoGeneratedKeys = autoGeneratedKeys;
416        this.columnIndexes = clone(columnIndexes);
417        this.columnNames = clone(columnNames);
418        this.statementBuilder = Objects.requireNonNull(Objects.requireNonNull(statementBuilder, "statementBuilder").apply(this), "statementBuilder");
419        this.statementType = statementType;
420    }
421
422    // Root constructor.
423    private PStmtKey(final String sql, final String catalog, final String schema, final Integer resultSetType, final Integer resultSetConcurrency,
424        final Integer resultSetHoldability, final Integer autoGeneratedKeys, final int[] columnIndexes, final String[] columnNames,
425        final StatementType statementType, final StatementBuilder statementBuilder) {
426        this.sql = sql;
427        this.catalog = catalog;
428        this.schema = schema;
429        this.resultSetType = resultSetType;
430        this.resultSetConcurrency = resultSetConcurrency;
431        this.resultSetHoldability = resultSetHoldability;
432        this.autoGeneratedKeys = autoGeneratedKeys;
433        this.columnIndexes = clone(columnIndexes);
434        this.columnNames = clone(columnNames);
435        this.statementBuilder = Objects.requireNonNull(statementBuilder, "statementBuilder");
436        this.statementType = statementType;
437    }
438
439    /**
440     * Constructs a key to uniquely identify a prepared statement.
441     *
442     * @param sql The SQL statement.
443     * @param catalog The catalog.
444     * @param schema The schema.
445     * @param statementType The SQL statement type, prepared or callable.
446     * @since 2.5.0
447     */
448    public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType) {
449        this(sql, catalog, schema, null, null, null, null, null, null, statementType, k -> match(statementType, StatementSQL, CallSQL));
450    }
451
452    /**
453     * Constructs a key to uniquely identify a prepared statement.
454     *
455     * @param sql The SQL statement.
456     * @param catalog The catalog.
457     * @param schema The schema.
458     * @param statementType The SQL statement type, prepared or callable.
459     * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
460     *        {@link Statement#RETURN_GENERATED_KEYS} or {@link Statement#NO_GENERATED_KEYS}.
461     * @since 2.5.0
462     */
463    public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType, final Integer autoGeneratedKeys) {
464        this(sql, catalog, schema, null, null, null, autoGeneratedKeys, null, null, statementType,
465            k -> match(statementType, StatementAutoGeneratedKeys, CallSQL));
466    }
467
468    /**
469     * Constructs a key to uniquely identify a prepared statement.
470     *
471     * @param sql The SQL statement.
472     * @param catalog The catalog.
473     * @param schema The schema.
474     * @param columnNames An array of column names indicating the columns that should be returned from the inserted row or
475     *        rows.
476     * @since 2.5.0
477     */
478    public PStmtKey(final String sql, final String catalog, final String schema, final String[] columnNames) {
479        this(sql, catalog, schema, null, null, null, null, null, columnNames, StatementType.PREPARED_STATEMENT, StatementColumnNames);
480    }
481
482    /**
483     * Constructs a key to uniquely identify a prepared statement.
484     *
485     * @param sql The SQL statement.
486     * @param catalog The catalog.
487     * @param columnNames An array of column names indicating the columns that should be returned from the inserted row or
488     *        rows.
489     * @deprecated Use {@link #PStmtKey(String, String, String, String[])}.
490     */
491    @Deprecated
492    public PStmtKey(final String sql, final String catalog, final String[] columnNames) {
493        this(sql, catalog, null, null, null, null, null, null, columnNames, StatementType.PREPARED_STATEMENT, StatementColumnNames);
494    }
495
496    private int[] clone(final int[] array) {
497        return array == null ? null : array.clone();
498    }
499
500    private String[] clone(final String[] array) {
501        return array == null ? null : array.clone();
502    }
503
504    /**
505     * Creates a new Statement from the given Connection.
506     *
507     * @param connection The Connection to use to create the statement.
508     * @return The statement.
509     * @throws SQLException Thrown when there is a problem creating the statement.
510     */
511    public Statement createStatement(final Connection connection) throws SQLException {
512        return statementBuilder.createStatement(connection, this);
513    }
514
515    @Override
516    public boolean equals(final Object obj) {
517        if (this == obj) {
518            return true;
519        }
520        if (obj == null || getClass() != obj.getClass()) {
521            return false;
522        }
523        final PStmtKey other = (PStmtKey) obj;
524        if (!Objects.equals(autoGeneratedKeys, other.autoGeneratedKeys) || !Objects.equals(catalog, other.catalog)
525                || !Arrays.equals(columnIndexes, other.columnIndexes) || !Arrays.equals(columnNames, other.columnNames)) {
526            return false;
527        }
528        if (!Objects.equals(resultSetConcurrency, other.resultSetConcurrency) || !Objects.equals(resultSetHoldability, other.resultSetHoldability)
529                || !Objects.equals(resultSetType, other.resultSetType) || !Objects.equals(schema, other.schema)) {
530            return false;
531        }
532        if (!Objects.equals(sql, other.sql)) {
533            return false;
534        }
535        return statementType == other.statementType;
536    }
537
538    /**
539     * Gets a flag indicating whether auto-generated keys should be returned; one of {@link Statement#RETURN_GENERATED_KEYS}
540     * or {@link Statement#NO_GENERATED_KEYS}.
541     *
542     * @return a flag indicating whether auto-generated keys should be returned.
543     */
544    public Integer getAutoGeneratedKeys() {
545        return autoGeneratedKeys;
546    }
547
548    /**
549     * Gets the catalog.
550     *
551     * @return The catalog.
552     */
553    public String getCatalog() {
554        return catalog;
555    }
556
557    /**
558     * Gets an array of column indexes indicating the columns that should be returned from the inserted row or rows.
559     *
560     * @return An array of column indexes.
561     */
562    public int[] getColumnIndexes() {
563        return clone(columnIndexes);
564    }
565
566    /**
567     * Gets an array of column names indicating the columns that should be returned from the inserted row or rows.
568     *
569     * @return An array of column names.
570     */
571    public String[] getColumnNames() {
572        return clone(columnNames);
573    }
574
575    /**
576     * Gets the result set concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
577     * {@link ResultSet#CONCUR_UPDATABLE}.
578     *
579     * @return The result set concurrency type.
580     */
581    public Integer getResultSetConcurrency() {
582        return resultSetConcurrency;
583    }
584
585    /**
586     * Gets the result set holdability, one of the following {@link ResultSet} constants:
587     * {@link ResultSet#HOLD_CURSORS_OVER_COMMIT} or {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}.
588     *
589     * @return The result set holdability.
590     */
591    public Integer getResultSetHoldability() {
592        return resultSetHoldability;
593    }
594
595    /**
596     * Gets the result set type, one of {@link ResultSet#TYPE_FORWARD_ONLY}, {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or
597     * {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
598     *
599     * @return the result set type.
600     */
601    public Integer getResultSetType() {
602        return resultSetType;
603    }
604
605    /**
606     * Gets the schema.
607     *
608     * @return The catalog.
609     */
610    public String getSchema() {
611        return schema;
612    }
613
614    /**
615     * Gets the SQL statement.
616     *
617     * @return the SQL statement.
618     */
619    public String getSql() {
620        return sql;
621    }
622
623    /**
624     * Gets the SQL statement type.
625     *
626     * @return The SQL statement type.
627     */
628    public StatementType getStmtType() {
629        return statementType;
630    }
631
632    @Override
633    public int hashCode() {
634        return Objects.hash(autoGeneratedKeys, catalog, Arrays.hashCode(columnIndexes), Arrays.hashCode(columnNames), resultSetConcurrency,
635            resultSetHoldability, resultSetType, schema, sql, statementType);
636    }
637
638    @Override
639    public String toString() {
640        final StringBuilder buf = new StringBuilder();
641        buf.append("PStmtKey: sql=");
642        buf.append(sql);
643        buf.append(", catalog=");
644        buf.append(catalog);
645        buf.append(", schema=");
646        buf.append(schema);
647        buf.append(", resultSetType=");
648        buf.append(resultSetType);
649        buf.append(", resultSetConcurrency=");
650        buf.append(resultSetConcurrency);
651        buf.append(", resultSetHoldability=");
652        buf.append(resultSetHoldability);
653        buf.append(", autoGeneratedKeys=");
654        buf.append(autoGeneratedKeys);
655        buf.append(", columnIndexes=");
656        buf.append(Arrays.toString(columnIndexes));
657        buf.append(", columnNames=");
658        buf.append(Arrays.toString(columnNames));
659        buf.append(", statementType=");
660        buf.append(statementType);
661        return buf.toString();
662    }
663}