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