    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}