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    *      http://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.SQLException;
21  import java.sql.Statement;
22  import java.util.Arrays;
23  import java.util.Objects;
24  import java.util.function.Function;
25  
26  import org.apache.commons.dbcp2.PoolingConnection.StatementType;
27  
28  /**
29   * A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s.
30   *
31   * @since 2.0
32   */
33  public class PStmtKey {
34  
35      /**
36       * Interface for Prepared or Callable Statement.
37       */
38      @FunctionalInterface
39      private interface StatementBuilder {
40          Statement createStatement(Connection connection, PStmtKey key) throws SQLException;
41      }
42  
43      private static final StatementBuilder CallConcurrency = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency);
44      private static final StatementBuilder CallHoldability = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency, k.resultSetHoldability);
45      private static final StatementBuilder CallSQL = (c, k) -> c.prepareCall(k.sql);
46      private static final StatementBuilder StatementAutoGeneratedKeys = (c, k) -> c.prepareStatement(k.sql, k.autoGeneratedKeys);
47      private static final StatementBuilder StatementColumnIndexes = (c, k) -> c.prepareStatement(k.sql, k.columnIndexes);
48      private static final StatementBuilder StatementColumnNames = (c, k) -> c.prepareStatement(k.sql, k.columnNames);
49      private static final StatementBuilder StatementConcurrency = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency);
50      private static final StatementBuilder StatementHoldability = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency,
51          k.resultSetHoldability);
52      private static final StatementBuilder StatementSQL = (c, k) -> c.prepareStatement(k.sql);
53  
54      private static StatementBuilder match(final StatementType statementType, final StatementBuilder prep, final StatementBuilder call) {
55          switch (Objects.requireNonNull(statementType, "statementType")) {
56          case PREPARED_STATEMENT:
57              return prep;
58          case CALLABLE_STATEMENT:
59              return call;
60          default:
61              throw new IllegalArgumentException(statementType.toString());
62          }
63      }
64  
65      /**
66       * SQL defining Prepared or Callable Statement
67       */
68      private final String sql;
69  
70      /**
71       * Result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or
72       * {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
73       */
74      private final Integer resultSetType;
75  
76      /**
77       * Result set concurrency. A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
78       * {@code ResultSet.CONCUR_UPDATABLE}.
79       */
80      private final Integer resultSetConcurrency;
81  
82      /**
83       * Result set holdability. One of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT}
84       * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
85       */
86      private final Integer resultSetHoldability;
87  
88      /**
89       * Database catalog.
90       */
91      private final String catalog;
92  
93      /**
94       * Database schema.
95       */
96      private final String schema;
97  
98      /**
99       * 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 }