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.PreparedStatement; 021import java.sql.SQLException; 022import java.sql.Statement; 023import java.util.Arrays; 024 025import org.apache.commons.dbcp2.PoolingConnection.StatementType; 026 027/** 028 * A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s. 029 * @since 2.0 030 */ 031public class PStmtKey { 032 033 /** SQL defining Prepared or Callable Statement */ 034 private final String _sql; 035 036 /** Result set type */ 037 private final Integer _resultSetType; 038 039 /** Result set concurrency */ 040 private final Integer _resultSetConcurrency; 041 042 /** Result set holdability */ 043 private final Integer _resultSetHoldability; 044 045 /** Database catalog */ 046 private final String _catalog; 047 048 /** Auto generated keys */ 049 private final Integer _autoGeneratedKeys; 050 051 /** column indexes */ 052 private final int[] _columnIndexes; 053 054 /** column names */ 055 private final String[] _columnNames; 056 057 /** Statement type */ 058 private final StatementType _stmtType; 059 060 /** Statement builder */ 061 private StatementBuilder builder; 062 063 public PStmtKey(final String sql) { 064 this(sql, null, StatementType.PREPARED_STATEMENT); 065 } 066 067 public PStmtKey(final String sql, final String catalog) { 068 this(sql, catalog, StatementType.PREPARED_STATEMENT); 069 } 070 071 public PStmtKey(final String sql, final String catalog, final StatementType stmtType) { 072 _sql = sql; 073 _catalog = catalog; 074 _stmtType = stmtType; 075 _autoGeneratedKeys = null; 076 _columnIndexes = null; 077 _columnNames = null; 078 _resultSetType = null; 079 _resultSetConcurrency = null; 080 _resultSetHoldability = null; 081 // create builder 082 if (stmtType == StatementType.PREPARED_STATEMENT) { 083 builder = new PreparedStatementSQL(); 084 } else if (stmtType == StatementType.CALLABLE_STATEMENT) { 085 builder = new PreparedCallSQL(); 086 } 087 } 088 089 public PStmtKey(final String sql, final String catalog, final int autoGeneratedKeys) { 090 this(sql, catalog, StatementType.PREPARED_STATEMENT, Integer.valueOf(autoGeneratedKeys)); 091 } 092 093 public PStmtKey(final String sql, final String catalog, final StatementType stmtType, final Integer autoGeneratedKeys) { 094 _sql = sql; 095 _catalog = catalog; 096 _stmtType = stmtType; 097 _autoGeneratedKeys = autoGeneratedKeys; 098 _columnIndexes = null; 099 _columnNames = null; 100 _resultSetType = null; 101 _resultSetConcurrency = null; 102 _resultSetHoldability = null; 103 // create builder 104 if (stmtType == StatementType.PREPARED_STATEMENT) { 105 builder = new PreparedStatementWithAutoGeneratedKeys(); 106 } else if (stmtType == StatementType.CALLABLE_STATEMENT) { 107 builder = new PreparedCallSQL(); 108 } 109 } 110 111 public PStmtKey(final String sql, final String catalog, final int[] columnIndexes) { 112 _sql = sql; 113 _catalog = catalog; 114 _stmtType = StatementType.PREPARED_STATEMENT; 115 _autoGeneratedKeys = null; 116 _columnIndexes = columnIndexes; 117 _columnNames = null; 118 _resultSetType = null; 119 _resultSetConcurrency = null; 120 _resultSetHoldability = null; 121 // create builder 122 builder = new PreparedStatementWithColumnIndexes(); 123 } 124 125 public PStmtKey(final String sql, final String catalog, final String[] columnNames) { 126 _sql = sql; 127 _catalog = catalog; 128 _stmtType = StatementType.PREPARED_STATEMENT; 129 _autoGeneratedKeys = null; 130 _columnIndexes = null; 131 _columnNames = columnNames; 132 _resultSetType = null; 133 _resultSetConcurrency = null; 134 _resultSetHoldability = null; 135 // create builder 136 builder = new PreparedStatementWithColumnNames(); 137 } 138 139 public PStmtKey(final String sql, final int resultSetType, final int resultSetConcurrency) { 140 this(sql, null, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT); 141 } 142 143 public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency) { 144 this(sql, catalog, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT); 145 } 146 147 public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final StatementType stmtType) { 148 _sql = sql; 149 _catalog = catalog; 150 _resultSetType = Integer.valueOf(resultSetType); 151 _resultSetConcurrency = Integer.valueOf(resultSetConcurrency); 152 _resultSetHoldability = null; 153 _stmtType = stmtType; 154 _autoGeneratedKeys = null; 155 _columnIndexes = null; 156 _columnNames = null; 157 // create builder 158 if (stmtType == StatementType.PREPARED_STATEMENT) { 159 builder = new PreparedStatementWithResultSetConcurrency(); 160 } else if (stmtType == StatementType.CALLABLE_STATEMENT) { 161 builder = new PreparedCallWithResultSetConcurrency(); 162 } 163 } 164 165 public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, 166 final int resultSetHoldability) { 167 this(sql, catalog, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT); 168 } 169 170 public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, 171 final int resultSetHoldability, final StatementType stmtType) { 172 _sql = sql; 173 _catalog = catalog; 174 _resultSetType = Integer.valueOf(resultSetType); 175 _resultSetConcurrency = Integer.valueOf(resultSetConcurrency); 176 _resultSetHoldability = Integer.valueOf(resultSetHoldability); 177 _stmtType = stmtType; 178 _autoGeneratedKeys = null; 179 _columnIndexes = null; 180 _columnNames = null; 181 // create builder 182 if (stmtType == StatementType.PREPARED_STATEMENT) { 183 builder = new PreparedStatementWithResultSetHoldability(); 184 } else if (stmtType == StatementType.CALLABLE_STATEMENT) { 185 builder = new PreparedCallWithResultSetHoldability(); 186 } 187 } 188 189 190 public String getSql() { 191 return _sql; 192 } 193 194 public Integer getResultSetType() { 195 return _resultSetType; 196 } 197 198 public Integer getResultSetConcurrency() { 199 return _resultSetConcurrency; 200 } 201 202 public Integer getResultSetHoldability() { 203 return _resultSetHoldability; 204 } 205 206 public Integer getAutoGeneratedKeys() { 207 return _autoGeneratedKeys; 208 } 209 210 public int[] getColumnIndexes() { 211 return _columnIndexes; 212 } 213 214 public String[] getColumnNames() { 215 return _columnNames; 216 } 217 218 public String getCatalog() { 219 return _catalog; 220 } 221 222 public StatementType getStmtType() { 223 return _stmtType; 224 } 225 226 @Override 227 public boolean equals(final Object obj) { 228 if (this == obj) { 229 return true; 230 } 231 if (obj == null) { 232 return false; 233 } 234 if (getClass() != obj.getClass()) { 235 return false; 236 } 237 final PStmtKey other = (PStmtKey) obj; 238 if (_catalog == null) { 239 if (other._catalog != null) { 240 return false; 241 } 242 } else if (!_catalog.equals(other._catalog)) { 243 return false; 244 } 245 if (_resultSetConcurrency == null) { 246 if (other._resultSetConcurrency != null) { 247 return false; 248 } 249 } else if (!_resultSetConcurrency.equals(other._resultSetConcurrency)) { 250 return false; 251 } 252 if (_resultSetType == null) { 253 if (other._resultSetType != null) { 254 return false; 255 } 256 } else if (!_resultSetType.equals(other._resultSetType)) { 257 return false; 258 } 259 if (_resultSetHoldability == null) { 260 if (other._resultSetHoldability != null) { 261 return false; 262 } 263 } else if (!_resultSetHoldability.equals(other._resultSetHoldability)) { 264 return false; 265 } 266 if (_autoGeneratedKeys == null) { 267 if (other._autoGeneratedKeys != null) { 268 return false; 269 } 270 } else if (!_autoGeneratedKeys.equals(other._autoGeneratedKeys)) { 271 return false; 272 } 273 if (!Arrays.equals(_columnIndexes, other._columnIndexes)) { 274 return false; 275 } 276 if (!Arrays.equals(_columnNames, other._columnNames)) { 277 return false; 278 } 279 if (_sql == null) { 280 if (other._sql != null) { 281 return false; 282 } 283 } else if (!_sql.equals(other._sql)) { 284 return false; 285 } 286 if (_stmtType != other._stmtType) { 287 return false; 288 } 289 return true; 290 } 291 292 @Override 293 public int hashCode() { 294 final int prime = 31; 295 int result = 1; 296 result = prime * result + (_catalog == null ? 0 : _catalog.hashCode()); 297 result = prime * result + (_resultSetConcurrency == null ? 0 : _resultSetConcurrency.hashCode()); 298 result = prime * result + (_resultSetType == null ? 0 : _resultSetType.hashCode()); 299 result = prime * result + (_resultSetHoldability == null ? 0 : _resultSetHoldability.hashCode()); 300 result = prime * result + (_sql == null ? 0 : _sql.hashCode()); 301 result = prime * result + (_autoGeneratedKeys == null ? 0 : _autoGeneratedKeys.hashCode()); 302 result = prime * result + Arrays.hashCode(_columnIndexes); 303 result = prime * result + Arrays.hashCode(_columnNames); 304 result = prime * result + _stmtType.hashCode(); 305 return result; 306 } 307 308 @Override 309 public String toString() { 310 final StringBuffer buf = new StringBuffer(); 311 buf.append("PStmtKey: sql="); 312 buf.append(_sql); 313 buf.append(", catalog="); 314 buf.append(_catalog); 315 buf.append(", resultSetType="); 316 buf.append(_resultSetType); 317 buf.append(", resultSetConcurrency="); 318 buf.append(_resultSetConcurrency); 319 buf.append(", resultSetHoldability="); 320 buf.append(_resultSetHoldability); 321 buf.append(", autoGeneratedKeys="); 322 buf.append(_autoGeneratedKeys); 323 buf.append(", columnIndexes="); 324 buf.append(Arrays.toString(_columnIndexes)); 325 buf.append(", columnNames="); 326 buf.append(Arrays.toString(_columnNames)); 327 buf.append(", statementType="); 328 buf.append(_stmtType); 329 return buf.toString(); 330 } 331 332 public Statement createStatement(final Connection connection) throws SQLException { 333 if (builder == null) { 334 throw new IllegalStateException("Prepared statement key is invalid."); 335 } 336 return builder.createStatement(connection); 337 } 338 339 /** 340 * Interface for Prepared or Callable Statement 341 */ 342 private interface StatementBuilder { 343 public Statement createStatement(Connection connection) throws SQLException; 344 } 345 346 /** 347 * Builder for prepareStatement(String sql) 348 */ 349 private class PreparedStatementSQL implements StatementBuilder { 350 @Override 351 public Statement createStatement(final Connection connection) throws SQLException { 352 final PreparedStatement statement = connection.prepareStatement(_sql); 353 return statement; 354 } 355 } 356 357 /** 358 * Builder for prepareStatement(String sql, int autoGeneratedKeys) 359 */ 360 private class PreparedStatementWithAutoGeneratedKeys implements StatementBuilder { 361 @Override 362 public Statement createStatement(final Connection connection) throws SQLException { 363 final PreparedStatement statement = connection.prepareStatement( 364 _sql, _autoGeneratedKeys.intValue()); 365 return statement; 366 } 367 } 368 369 /** 370 * Builder for prepareStatement(String sql, int[] columnIndexes) 371 */ 372 private class PreparedStatementWithColumnIndexes implements StatementBuilder { 373 @Override 374 public Statement createStatement(final Connection connection) throws SQLException { 375 final PreparedStatement statement = connection.prepareStatement( 376 _sql, _columnIndexes); 377 return statement; 378 } 379 } 380 381 /** 382 * Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency) 383 */ 384 private class PreparedStatementWithResultSetConcurrency implements StatementBuilder { 385 @Override 386 public Statement createStatement(final Connection connection) throws SQLException { 387 final PreparedStatement statement = connection.prepareStatement( 388 _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue()); 389 return statement; 390 } 391 } 392 393 /** 394 * Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) 395 */ 396 private class PreparedStatementWithResultSetHoldability implements StatementBuilder { 397 @Override 398 public Statement createStatement(final Connection connection) throws SQLException { 399 final PreparedStatement statement = connection.prepareStatement( 400 _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue(), 401 _resultSetHoldability.intValue()); 402 return statement; 403 } 404 } 405 406 /** 407 * Builder for prepareStatement(String sql, String[] columnNames) 408 */ 409 private class PreparedStatementWithColumnNames implements StatementBuilder { 410 @Override 411 public Statement createStatement(final Connection connection) throws SQLException { 412 final PreparedStatement statement = connection.prepareStatement( 413 _sql, _columnNames); 414 return statement; 415 } 416 } 417 418 /** 419 * Builder for prepareCall(String sql) 420 */ 421 private class PreparedCallSQL implements StatementBuilder { 422 @Override 423 public Statement createStatement(final Connection connection) throws SQLException { 424 final PreparedStatement statement = connection.prepareCall(_sql); 425 return statement; 426 } 427 } 428 429 /** 430 * Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency) 431 */ 432 private class PreparedCallWithResultSetConcurrency implements StatementBuilder { 433 @Override 434 public Statement createStatement(final Connection connection) throws SQLException { 435 final PreparedStatement statement = connection.prepareCall( 436 _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue()); 437 return statement; 438 } 439 } 440 441 /** 442 * Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) 443 */ 444 private class PreparedCallWithResultSetHoldability implements StatementBuilder { 445 @Override 446 public Statement createStatement(final Connection connection) throws SQLException { 447 final PreparedStatement statement = connection.prepareCall( 448 _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue(), 449 _resultSetHoldability.intValue()); 450 return statement; 451 } 452 } 453}