View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.dbcp2;
18  
19  import java.sql.Connection;
20  import java.sql.ResultSet;
21  import java.sql.SQLException;
22  import java.sql.Statement;
23  import java.util.Arrays;
24  import java.util.Objects;
25  import java.util.function.Function;
26  
27  import org.apache.commons.dbcp2.PoolingConnection.StatementType;
28  
29  /**
30   * A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s.
31   *
32   * @since 2.0
33   */
34  public class PStmtKey {
35  
36      /**
37       * Interface for Prepared or Callable Statement.
38       */
39      @FunctionalInterface
40      private interface StatementBuilder {
41          Statement createStatement(Connection connection, PStmtKey key) throws SQLException;
42      }
43  
44      private static final StatementBuilder CallConcurrency = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency);
45      private static final StatementBuilder CallHoldability = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency, k.resultSetHoldability);
46      private static final StatementBuilder CallSQL = (c, k) -> c.prepareCall(k.sql);
47      private static final StatementBuilder StatementAutoGeneratedKeys = (c, k) -> c.prepareStatement(k.sql, k.autoGeneratedKeys);
48      private static final StatementBuilder StatementColumnIndexes = (c, k) -> c.prepareStatement(k.sql, k.columnIndexes);
49      private static final StatementBuilder StatementColumnNames = (c, k) -> c.prepareStatement(k.sql, k.columnNames);
50      private static final StatementBuilder StatementConcurrency = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency);
51      private static final StatementBuilder StatementHoldability = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency,
52          k.resultSetHoldability);
53      private static final StatementBuilder StatementSQL = (c, k) -> c.prepareStatement(k.sql);
54  
55      private static StatementBuilder match(final StatementType statementType, final StatementBuilder prep, final StatementBuilder call) {
56          switch (Objects.requireNonNull(statementType, "statementType")) {
57          case PREPARED_STATEMENT:
58              return prep;
59          case CALLABLE_STATEMENT:
60              return call;
61          default:
62              throw new IllegalArgumentException(statementType.toString());
63          }
64      }
65  
66      /**
67       * SQL defining Prepared or Callable Statement
68       */
69      private final String sql;
70  
71      /**
72       * Result set type; one of {@link ResultSet#TYPE_FORWARD_ONLY}, {@link ResultSet#TYPE_SCROLL_INSENSITIVE}, or
73       * {@link ResultSet#TYPE_SCROLL_SENSITIVE}.
74       */
75      private final Integer resultSetType;
76  
77      /**
78       * Result set concurrency. A concurrency type; one of {@link ResultSet#CONCUR_READ_ONLY} or
79       * {@link ResultSet#CONCUR_UPDATABLE}.
80       */
81      private final Integer resultSetConcurrency;
82  
83      /**
84       * Result set holdability. One of the following {@link ResultSet} constants: {@link ResultSet#HOLD_CURSORS_OVER_COMMIT}
85       * or {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}.
86       */
87      private final Integer resultSetHoldability;
88  
89      /**
90       * Database catalog.
91       */
92      private final String catalog;
93  
94      /**
95       * Database schema.
96       */
97      private final String schema;
98  
99      /**
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 }