PStmtKey.java

  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. import java.sql.Connection;
  19. import java.sql.SQLException;
  20. import java.sql.Statement;
  21. import java.util.Arrays;
  22. import java.util.Objects;
  23. import java.util.function.Function;

  24. import org.apache.commons.dbcp2.PoolingConnection.StatementType;

  25. /**
  26.  * A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s.
  27.  *
  28.  * @since 2.0
  29.  */
  30. public class PStmtKey {

  31.     /**
  32.      * Interface for Prepared or Callable Statement.
  33.      */
  34.     @FunctionalInterface
  35.     private interface StatementBuilder {
  36.         Statement createStatement(Connection connection, PStmtKey key) throws SQLException;
  37.     }

  38.     private static final StatementBuilder CallConcurrency = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency);
  39.     private static final StatementBuilder CallHoldability = (c, k) -> c.prepareCall(k.sql, k.resultSetType, k.resultSetConcurrency, k.resultSetHoldability);
  40.     private static final StatementBuilder CallSQL = (c, k) -> c.prepareCall(k.sql);
  41.     private static final StatementBuilder StatementAutoGeneratedKeys = (c, k) -> c.prepareStatement(k.sql, k.autoGeneratedKeys);
  42.     private static final StatementBuilder StatementColumnIndexes = (c, k) -> c.prepareStatement(k.sql, k.columnIndexes);
  43.     private static final StatementBuilder StatementColumnNames = (c, k) -> c.prepareStatement(k.sql, k.columnNames);
  44.     private static final StatementBuilder StatementConcurrency = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency);
  45.     private static final StatementBuilder StatementHoldability = (c, k) -> c.prepareStatement(k.sql, k.resultSetType, k.resultSetConcurrency,
  46.         k.resultSetHoldability);
  47.     private static final StatementBuilder StatementSQL = (c, k) -> c.prepareStatement(k.sql);

  48.     private static StatementBuilder match(final StatementType statementType, final StatementBuilder prep, final StatementBuilder call) {
  49.         switch (Objects.requireNonNull(statementType, "statementType")) {
  50.         case PREPARED_STATEMENT:
  51.             return prep;
  52.         case CALLABLE_STATEMENT:
  53.             return call;
  54.         default:
  55.             throw new IllegalArgumentException(statementType.toString());
  56.         }
  57.     }

  58.     /**
  59.      * SQL defining Prepared or Callable Statement
  60.      */
  61.     private final String sql;

  62.     /**
  63.      * Result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY}, {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or
  64.      * {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  65.      */
  66.     private final Integer resultSetType;

  67.     /**
  68.      * Result set concurrency. A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  69.      * {@code ResultSet.CONCUR_UPDATABLE}.
  70.      */
  71.     private final Integer resultSetConcurrency;

  72.     /**
  73.      * Result set holdability. One of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT}
  74.      * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
  75.      */
  76.     private final Integer resultSetHoldability;

  77.     /**
  78.      * Database catalog.
  79.      */
  80.     private final String catalog;

  81.     /**
  82.      * Database schema.
  83.      */
  84.     private final String schema;

  85.     /**
  86.      * A flag indicating whether auto-generated keys should be returned; one of {@code Statement.RETURN_GENERATED_KEYS} or
  87.      * {@code Statement.NO_GENERATED_KEYS}.
  88.      */
  89.     private final Integer autoGeneratedKeys;

  90.     /**
  91.      * An array of column indexes indicating the columns that should be returned from the inserted row or rows.
  92.      */
  93.     private final int[] columnIndexes;

  94.     /**
  95.      * An array of column names indicating the columns that should be returned from the inserted row or rows.
  96.      */
  97.     private final String[] columnNames;

  98.     /**
  99.      * Statement builder.
  100.      */
  101.     private final transient StatementBuilder statementBuilder;

  102.     /**
  103.      * Statement type, prepared or callable.
  104.      */
  105.     private final StatementType statementType;

  106.     /**
  107.      * Constructs a key to uniquely identify a prepared statement.
  108.      *
  109.      * @param sql The SQL statement.
  110.      * @deprecated Use {@link #PStmtKey(String, String, String)}.
  111.      */
  112.     @Deprecated
  113.     public PStmtKey(final String sql) {
  114.         this(sql, null, StatementType.PREPARED_STATEMENT);
  115.     }

  116.     /**
  117.      * Constructs a key to uniquely identify a prepared statement.
  118.      *
  119.      * @param sql The SQL statement.
  120.      * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  121.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  122.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  123.      *        {@code ResultSet.CONCUR_UPDATABLE}.
  124.      * @deprecated Use {@link #PStmtKey(String, String, String, int, int)}.
  125.      */
  126.     @Deprecated
  127.     public PStmtKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
  128.         this(sql, null, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
  129.     }

  130.     /**
  131.      * Constructs a key to uniquely identify a prepared statement.
  132.      *
  133.      * @param sql The SQL statement.
  134.      * @param catalog The catalog.
  135.      * @deprecated Use {@link #PStmtKey(String, String, String)}.
  136.      */
  137.     @Deprecated
  138.     public PStmtKey(final String sql, final String catalog) {
  139.         this(sql, catalog, StatementType.PREPARED_STATEMENT);
  140.     }

  141.     /**
  142.      * Constructs a key to uniquely identify a prepared statement.
  143.      *
  144.      * @param sql The SQL statement.
  145.      * @param catalog The catalog.
  146.      * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
  147.      *        {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}.
  148.      * @deprecated Use {@link #PStmtKey(String, String, String, int)}.
  149.      */
  150.     @Deprecated
  151.     public PStmtKey(final String sql, final String catalog, final int autoGeneratedKeys) {
  152.         this(sql, catalog, StatementType.PREPARED_STATEMENT, autoGeneratedKeys);
  153.     }

  154.     /**
  155.      * Constructs a key to uniquely identify a prepared statement.
  156.      *
  157.      * @param sql The SQL statement.
  158.      * @param catalog The catalog.
  159.      * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  160.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  161.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  162.      *        {@code ResultSet.CONCUR_UPDATABLE}.
  163.      * @deprecated Use {@link #PStmtKey(String, String, String, int, int)}.
  164.      */
  165.     @Deprecated
  166.     public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency) {
  167.         this(sql, catalog, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
  168.     }

  169.     /**
  170.      * Constructs a key to uniquely identify a prepared statement.
  171.      *
  172.      * @param sql The SQL statement.
  173.      * @param catalog The catalog.
  174.      * @param resultSetType a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  175.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  176.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  177.      *        {@code ResultSet.CONCUR_UPDATABLE}
  178.      * @param resultSetHoldability One of the following {@code ResultSet} constants:
  179.      *        {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
  180.      * @deprecated Use {@link #PStmtKey(String, String, String, int, int, int)}.
  181.      */
  182.     @Deprecated
  183.     public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) {
  184.         this(sql, catalog, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT);
  185.     }

  186.     /**
  187.      * Constructs a key to uniquely identify a prepared statement.
  188.      *
  189.      * @param sql The SQL statement.
  190.      * @param catalog The catalog.
  191.      * @param resultSetType a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  192.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}
  193.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  194.      *        {@code ResultSet.CONCUR_UPDATABLE}.
  195.      * @param resultSetHoldability One of the following {@code ResultSet} constants:
  196.      *        {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
  197.      * @param statementType The SQL statement type, prepared or callable.
  198.      * @deprecated Use {@link #PStmtKey(String, String, String, int, int, int, PoolingConnection.StatementType)}
  199.      */
  200.     @Deprecated
  201.     public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability,
  202.         final StatementType statementType) {
  203.         this(sql, catalog, null, resultSetType, resultSetConcurrency, resultSetHoldability, null, null, null, statementType,
  204.             k -> match(statementType, StatementHoldability, CallHoldability));
  205.     }

  206.     /**
  207.      * Constructs a key to uniquely identify a prepared statement.
  208.      *
  209.      * @param sql The SQL statement.
  210.      * @param catalog The catalog.
  211.      * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  212.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  213.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  214.      *        {@code ResultSet.CONCUR_UPDATABLE}.
  215.      * @param statementType The SQL statement type, prepared or callable.
  216.      * @deprecated Use {@link #PStmtKey(String, String, String, int, int, PoolingConnection.StatementType)}.
  217.      */
  218.     @Deprecated
  219.     public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final StatementType statementType) {
  220.         this(sql, catalog, null, resultSetType, resultSetConcurrency, null, null, null, null, statementType,
  221.             k -> match(statementType, StatementConcurrency, CallConcurrency));
  222.     }

  223.     /**
  224.      * Constructs a key to uniquely identify a prepared statement.
  225.      *
  226.      * @param sql The SQL statement.
  227.      * @param catalog The catalog.
  228.      * @param columnIndexes An array of column indexes indicating the columns that should be returned from the inserted row
  229.      *        or rows.
  230.      * @deprecated Use {@link #PStmtKey(String, String, String, int[])}.
  231.      */
  232.     @Deprecated
  233.     public PStmtKey(final String sql, final String catalog, final int[] columnIndexes) {
  234.         this(sql, catalog, null, null, null, null, null, columnIndexes, null, StatementType.PREPARED_STATEMENT, StatementColumnIndexes);
  235.     }

  236.     /**
  237.      * Constructs a key to uniquely identify a prepared statement.
  238.      *
  239.      * @param sql The SQL statement.
  240.      * @param catalog The catalog.
  241.      * @param statementType The SQL statement type, prepared or callable.
  242.      * @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType)}.
  243.      */
  244.     @Deprecated
  245.     public PStmtKey(final String sql, final String catalog, final StatementType statementType) {
  246.         this(sql, catalog, null, null, null, null, null, null, null, statementType, k -> match(statementType, StatementSQL, CallSQL));
  247.     }

  248.     /**
  249.      * Constructs a key to uniquely identify a prepared statement.
  250.      *
  251.      * @param sql The SQL statement.
  252.      * @param catalog The catalog.
  253.      * @param statementType The SQL statement type, prepared or callable.
  254.      * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
  255.      *        {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}.
  256.      * @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType, Integer)}
  257.      */
  258.     @Deprecated
  259.     public PStmtKey(final String sql, final String catalog, final StatementType statementType, final Integer autoGeneratedKeys) {
  260.         this(sql, catalog, null, null, null, null, autoGeneratedKeys, null, null, statementType,
  261.             k -> match(statementType, StatementAutoGeneratedKeys, CallSQL));
  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 schema The schema
  269.      * @since 2.5.0
  270.      */
  271.     public PStmtKey(final String sql, final String catalog, final String schema) {
  272.         this(sql, catalog, schema, StatementType.PREPARED_STATEMENT);
  273.     }

  274.     /**
  275.      * Constructs a key to uniquely identify a prepared statement.
  276.      *
  277.      * @param sql The SQL statement.
  278.      * @param catalog The catalog.
  279.      * @param schema The schema
  280.      * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
  281.      *        {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}.
  282.      * @since 2.5.0
  283.      */
  284.     public PStmtKey(final String sql, final String catalog, final String schema, final int autoGeneratedKeys) {
  285.         this(sql, catalog, schema, StatementType.PREPARED_STATEMENT, autoGeneratedKeys);
  286.     }

  287.     /**
  288.      * Constructs a key to uniquely identify a prepared statement.
  289.      *
  290.      * @param sql The SQL statement.
  291.      * @param catalog The catalog.
  292.      * @param schema The schema
  293.      * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  294.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  295.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  296.      *        {@code ResultSet.CONCUR_UPDATABLE}.
  297.      */
  298.     public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency) {
  299.         this(sql, catalog, schema, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
  300.     }

  301.     /**
  302.      * Constructs a key to uniquely identify a prepared statement.
  303.      *
  304.      * @param sql The SQL statement.
  305.      * @param catalog The catalog.
  306.      * @param schema The schema
  307.      * @param resultSetType a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  308.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  309.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  310.      *        {@code ResultSet.CONCUR_UPDATABLE}
  311.      * @param resultSetHoldability One of the following {@code ResultSet} constants:
  312.      *        {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
  313.      * @since 2.5.0
  314.      */
  315.     public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
  316.         final int resultSetHoldability) {
  317.         this(sql, catalog, schema, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT);
  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 {@code ResultSet.TYPE_FORWARD_ONLY},
  326.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}
  327.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  328.      *        {@code ResultSet.CONCUR_UPDATABLE}.
  329.      * @param resultSetHoldability One of the following {@code ResultSet} constants:
  330.      *        {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
  331.      * @param statementType The SQL statement type, prepared or callable.
  332.      * @since 2.5.0
  333.      */
  334.     public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
  335.         final int resultSetHoldability, final StatementType statementType) {
  336.         this(sql, catalog, schema, resultSetType, resultSetConcurrency, resultSetHoldability, null, null, null, statementType,
  337.             k -> match(statementType, StatementHoldability, CallHoldability));
  338.     }

  339.     /**
  340.      * Constructs a key to uniquely identify a prepared statement.
  341.      *
  342.      * @param sql The SQL statement.
  343.      * @param catalog The catalog.
  344.      * @param schema The schema.
  345.      * @param resultSetType A result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
  346.      *        {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  347.      * @param resultSetConcurrency A concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  348.      *        {@code ResultSet.CONCUR_UPDATABLE}.
  349.      * @param statementType The SQL statement type, prepared or callable.
  350.      * @since 2.5.0
  351.      */
  352.     public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
  353.         final StatementType statementType) {
  354.         this(sql, catalog, schema, resultSetType, resultSetConcurrency, null, null, null, null, statementType,
  355.             k -> match(statementType, StatementConcurrency, CallConcurrency));
  356.     }

  357.     /**
  358.      * Constructs a key to uniquely identify a prepared statement.
  359.      *
  360.      * @param sql The SQL statement.
  361.      * @param catalog The catalog.
  362.      * @param schema The schema.
  363.      * @param columnIndexes An array of column indexes indicating the columns that should be returned from the inserted row
  364.      *        or rows.
  365.      */
  366.     public PStmtKey(final String sql, final String catalog, final String schema, final int[] columnIndexes) {
  367.         this(sql, catalog, schema, null, null, null, null, columnIndexes, null, StatementType.PREPARED_STATEMENT, StatementColumnIndexes);
  368.     }

  369.     private PStmtKey(final String sql, final String catalog, final String schema, final Integer resultSetType, final Integer resultSetConcurrency,
  370.         final Integer resultSetHoldability, final Integer autoGeneratedKeys, final int[] columnIndexes, final String[] columnNames,
  371.         final StatementType statementType, final Function<PStmtKey, StatementBuilder> statementBuilder) {
  372.         this.sql = Objects.requireNonNull(sql, "sql").trim();
  373.         this.catalog = catalog;
  374.         this.schema = schema;
  375.         this.resultSetType = resultSetType;
  376.         this.resultSetConcurrency = resultSetConcurrency;
  377.         this.resultSetHoldability = resultSetHoldability;
  378.         this.autoGeneratedKeys = autoGeneratedKeys;
  379.         this.columnIndexes = clone(columnIndexes);
  380.         this.columnNames = clone(columnNames);
  381.         this.statementBuilder = Objects.requireNonNull(Objects.requireNonNull(statementBuilder, "statementBuilder").apply(this), "statementBuilder");
  382.         this.statementType = statementType;
  383.     }

  384.     // Root constructor.
  385.     private PStmtKey(final String sql, final String catalog, final String schema, final Integer resultSetType, final Integer resultSetConcurrency,
  386.         final Integer resultSetHoldability, final Integer autoGeneratedKeys, final int[] columnIndexes, final String[] columnNames,
  387.         final StatementType statementType, final StatementBuilder statementBuilder) {
  388.         this.sql = sql;
  389.         this.catalog = catalog;
  390.         this.schema = schema;
  391.         this.resultSetType = resultSetType;
  392.         this.resultSetConcurrency = resultSetConcurrency;
  393.         this.resultSetHoldability = resultSetHoldability;
  394.         this.autoGeneratedKeys = autoGeneratedKeys;
  395.         this.columnIndexes = clone(columnIndexes);
  396.         this.columnNames = clone(columnNames);
  397.         this.statementBuilder = Objects.requireNonNull(statementBuilder, "statementBuilder");
  398.         this.statementType = statementType;
  399.     }

  400.     /**
  401.      * Constructs a key to uniquely identify a prepared statement.
  402.      *
  403.      * @param sql The SQL statement.
  404.      * @param catalog The catalog.
  405.      * @param schema The schema.
  406.      * @param statementType The SQL statement type, prepared or callable.
  407.      * @since 2.5.0
  408.      */
  409.     public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType) {
  410.         this(sql, catalog, schema, null, null, null, null, null, null, statementType, k -> match(statementType, StatementSQL, CallSQL));
  411.     }

  412.     /**
  413.      * Constructs a key to uniquely identify a prepared statement.
  414.      *
  415.      * @param sql The SQL statement.
  416.      * @param catalog The catalog.
  417.      * @param schema The schema.
  418.      * @param statementType The SQL statement type, prepared or callable.
  419.      * @param autoGeneratedKeys A flag indicating whether auto-generated keys should be returned; one of
  420.      *        {@code Statement.RETURN_GENERATED_KEYS} or {@code Statement.NO_GENERATED_KEYS}.
  421.      * @since 2.5.0
  422.      */
  423.     public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType, final Integer autoGeneratedKeys) {
  424.         this(sql, catalog, schema, null, null, null, autoGeneratedKeys, null, null, statementType,
  425.             k -> match(statementType, StatementAutoGeneratedKeys, CallSQL));
  426.     }

  427.     /**
  428.      * Constructs a key to uniquely identify a prepared statement.
  429.      *
  430.      * @param sql The SQL statement.
  431.      * @param catalog The catalog.
  432.      * @param schema The schema.
  433.      * @param columnNames An array of column names indicating the columns that should be returned from the inserted row or
  434.      *        rows.
  435.      * @since 2.5.0
  436.      */
  437.     public PStmtKey(final String sql, final String catalog, final String schema, final String[] columnNames) {
  438.         this(sql, catalog, schema, null, null, null, null, null, columnNames, StatementType.PREPARED_STATEMENT, StatementColumnNames);
  439.     }

  440.     /**
  441.      * Constructs a key to uniquely identify a prepared statement.
  442.      *
  443.      * @param sql The SQL statement.
  444.      * @param catalog The catalog.
  445.      * @param columnNames An array of column names indicating the columns that should be returned from the inserted row or
  446.      *        rows.
  447.      * @deprecated Use {@link #PStmtKey(String, String, String, String[])}.
  448.      */
  449.     @Deprecated
  450.     public PStmtKey(final String sql, final String catalog, final String[] columnNames) {
  451.         this(sql, catalog, null, null, null, null, null, null, columnNames, StatementType.PREPARED_STATEMENT, StatementColumnNames);
  452.     }

  453.     private int[] clone(final int[] array) {
  454.         return array == null ? null : array.clone();
  455.     }

  456.     private String[] clone(final String[] array) {
  457.         return array == null ? null : array.clone();
  458.     }

  459.     /**
  460.      * Creates a new Statement from the given Connection.
  461.      *
  462.      * @param connection The Connection to use to create the statement.
  463.      * @return The statement.
  464.      * @throws SQLException Thrown when there is a problem creating the statement.
  465.      */
  466.     public Statement createStatement(final Connection connection) throws SQLException {
  467.         return statementBuilder.createStatement(connection, this);
  468.     }

  469.     @Override
  470.     public boolean equals(final Object obj) {
  471.         if (this == obj) {
  472.             return true;
  473.         }
  474.         if (obj == null) {
  475.             return false;
  476.         }
  477.         if (getClass() != obj.getClass()) {
  478.             return false;
  479.         }
  480.         final PStmtKey other = (PStmtKey) obj;
  481.         if (!Objects.equals(autoGeneratedKeys, other.autoGeneratedKeys)) {
  482.             return false;
  483.         }
  484.         if (!Objects.equals(catalog, other.catalog)) {
  485.             return false;
  486.         }
  487.         if (!Arrays.equals(columnIndexes, other.columnIndexes)) {
  488.             return false;
  489.         }
  490.         if (!Arrays.equals(columnNames, other.columnNames)) {
  491.             return false;
  492.         }
  493.         if (!Objects.equals(resultSetConcurrency, other.resultSetConcurrency)) {
  494.             return false;
  495.         }
  496.         if (!Objects.equals(resultSetHoldability, other.resultSetHoldability)) {
  497.             return false;
  498.         }
  499.         if (!Objects.equals(resultSetType, other.resultSetType)) {
  500.             return false;
  501.         }
  502.         if (!Objects.equals(schema, other.schema)) {
  503.             return false;
  504.         }
  505.         if (!Objects.equals(sql, other.sql)) {
  506.             return false;
  507.         }
  508.         return statementType == other.statementType;
  509.     }

  510.     /**
  511.      * Gets a flag indicating whether auto-generated keys should be returned; one of {@code Statement.RETURN_GENERATED_KEYS}
  512.      * or {@code Statement.NO_GENERATED_KEYS}.
  513.      *
  514.      * @return a flag indicating whether auto-generated keys should be returned.
  515.      */
  516.     public Integer getAutoGeneratedKeys() {
  517.         return autoGeneratedKeys;
  518.     }

  519.     /**
  520.      * Gets the catalog.
  521.      *
  522.      * @return The catalog.
  523.      */
  524.     public String getCatalog() {
  525.         return catalog;
  526.     }

  527.     /**
  528.      * Gets an array of column indexes indicating the columns that should be returned from the inserted row or rows.
  529.      *
  530.      * @return An array of column indexes.
  531.      */
  532.     public int[] getColumnIndexes() {
  533.         return clone(columnIndexes);
  534.     }

  535.     /**
  536.      * Gets an array of column names indicating the columns that should be returned from the inserted row or rows.
  537.      *
  538.      * @return An array of column names.
  539.      */
  540.     public String[] getColumnNames() {
  541.         return clone(columnNames);
  542.     }

  543.     /**
  544.      * Gets the result set concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
  545.      * {@code ResultSet.CONCUR_UPDATABLE}.
  546.      *
  547.      * @return The result set concurrency type.
  548.      */
  549.     public Integer getResultSetConcurrency() {
  550.         return resultSetConcurrency;
  551.     }

  552.     /**
  553.      * Gets the result set holdability, one of the following {@code ResultSet} constants:
  554.      * {@code ResultSet.HOLD_CURSORS_OVER_COMMIT} or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
  555.      *
  556.      * @return The result set holdability.
  557.      */
  558.     public Integer getResultSetHoldability() {
  559.         return resultSetHoldability;
  560.     }

  561.     /**
  562.      * Gets the result set type, one of {@code ResultSet.TYPE_FORWARD_ONLY}, {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or
  563.      * {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
  564.      *
  565.      * @return the result set type.
  566.      */
  567.     public Integer getResultSetType() {
  568.         return resultSetType;
  569.     }

  570.     /**
  571.      * Gets the schema.
  572.      *
  573.      * @return The catalog.
  574.      */
  575.     public String getSchema() {
  576.         return schema;
  577.     }

  578.     /**
  579.      * Gets the SQL statement.
  580.      *
  581.      * @return the SQL statement.
  582.      */
  583.     public String getSql() {
  584.         return sql;
  585.     }

  586.     /**
  587.      * Gets the SQL statement type.
  588.      *
  589.      * @return The SQL statement type.
  590.      */
  591.     public StatementType getStmtType() {
  592.         return statementType;
  593.     }

  594.     @Override
  595.     public int hashCode() {
  596.         return Objects.hash(autoGeneratedKeys, catalog, Arrays.hashCode(columnIndexes), Arrays.hashCode(columnNames), resultSetConcurrency,
  597.             resultSetHoldability, resultSetType, schema, sql, statementType);
  598.     }

  599.     @Override
  600.     public String toString() {
  601.         final StringBuilder buf = new StringBuilder();
  602.         buf.append("PStmtKey: sql=");
  603.         buf.append(sql);
  604.         buf.append(", catalog=");
  605.         buf.append(catalog);
  606.         buf.append(", schema=");
  607.         buf.append(schema);
  608.         buf.append(", resultSetType=");
  609.         buf.append(resultSetType);
  610.         buf.append(", resultSetConcurrency=");
  611.         buf.append(resultSetConcurrency);
  612.         buf.append(", resultSetHoldability=");
  613.         buf.append(resultSetHoldability);
  614.         buf.append(", autoGeneratedKeys=");
  615.         buf.append(autoGeneratedKeys);
  616.         buf.append(", columnIndexes=");
  617.         buf.append(Arrays.toString(columnIndexes));
  618.         buf.append(", columnNames=");
  619.         buf.append(Arrays.toString(columnNames));
  620.         buf.append(", statementType=");
  621.         buf.append(statementType);
  622.         return buf.toString();
  623.     }
  624. }