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 */ 017 018package org.apache.commons.dbcp2; 019 020import java.sql.Array; 021import java.sql.Blob; 022import java.sql.CallableStatement; 023import java.sql.ClientInfoStatus; 024import java.sql.Clob; 025import java.sql.Connection; 026import java.sql.DatabaseMetaData; 027import java.sql.NClob; 028import java.sql.PreparedStatement; 029import java.sql.ResultSet; 030import java.sql.SQLClientInfoException; 031import java.sql.SQLException; 032import java.sql.SQLWarning; 033import java.sql.SQLXML; 034import java.sql.Savepoint; 035import java.sql.Statement; 036import java.sql.Struct; 037import java.util.ArrayList; 038import java.util.Collections; 039import java.util.Iterator; 040import java.util.List; 041import java.util.Map; 042import java.util.Properties; 043import java.util.concurrent.Executor; 044 045/** 046 * A base delegating implementation of {@link Connection}. 047 * <p> 048 * All of the methods from the {@link Connection} interface simply check to see that the {@link Connection} is active, 049 * and call the corresponding method on the "delegate" provided in my constructor. 050 * </p> 051 * <p> 052 * Extends AbandonedTrace to implement Connection tracking and logging of code which created the Connection. Tracking 053 * the Connection ensures that the AbandonedObjectPool can close this connection and recycle it if its pool of 054 * connections is nearing exhaustion and this connection's last usage is older than the removeAbandonedTimeout. 055 * </p> 056 * 057 * @param <C> 058 * the Connection type 059 * 060 * @since 2.0 061 */ 062public class DelegatingConnection<C extends Connection> extends AbandonedTrace implements Connection { 063 064 private static final Map<String, ClientInfoStatus> EMPTY_FAILED_PROPERTIES = Collections 065 .<String, ClientInfoStatus>emptyMap(); 066 067 /** My delegate {@link Connection}. */ 068 private volatile C connection; 069 070 private volatile boolean closed; 071 072 private boolean cacheState = true; 073 private Boolean autoCommitCached; 074 private Boolean readOnlyCached; 075 private Integer defaultQueryTimeoutSeconds; 076 077 /** 078 * Creates a wrapper for the Connection which traces this Connection in the AbandonedObjectPool. 079 * 080 * @param c 081 * the {@link Connection} to delegate all calls to. 082 */ 083 public DelegatingConnection(final C c) { 084 super(); 085 connection = c; 086 } 087 088 /** 089 * Returns a string representation of the metadata associated with the innermost delegate connection. 090 */ 091 @SuppressWarnings("resource") 092 @Override 093 public synchronized String toString() { 094 String str = null; 095 096 final Connection conn = this.getInnermostDelegateInternal(); 097 if (conn != null) { 098 try { 099 if (conn.isClosed()) { 100 str = "connection is closed"; 101 } else { 102 final StringBuffer sb = new StringBuffer(); 103 sb.append(hashCode()); 104 final DatabaseMetaData meta = conn.getMetaData(); 105 if (meta != null) { 106 sb.append(", URL="); 107 sb.append(meta.getURL()); 108 sb.append(", "); 109 sb.append(meta.getDriverName()); 110 str = sb.toString(); 111 } 112 } 113 } catch (final SQLException ex) { 114 // Ignore 115 } 116 } 117 return str != null ? str : super.toString(); 118 } 119 120 /** 121 * Returns my underlying {@link Connection}. 122 * 123 * @return my underlying {@link Connection}. 124 */ 125 public C getDelegate() { 126 return getDelegateInternal(); 127 } 128 129 protected final C getDelegateInternal() { 130 return connection; 131 } 132 133 /** 134 * Compares innermost delegate to the given connection. 135 * 136 * @param c 137 * connection to compare innermost delegate with 138 * @return true if innermost delegate equals <code>c</code> 139 */ 140 @SuppressWarnings("resource") 141 public boolean innermostDelegateEquals(final Connection c) { 142 final Connection innerCon = getInnermostDelegateInternal(); 143 if (innerCon == null) { 144 return c == null; 145 } 146 return innerCon.equals(c); 147 } 148 149 /** 150 * If my underlying {@link Connection} is not a {@code DelegatingConnection}, returns it, otherwise recursively 151 * invokes this method on my delegate. 152 * <p> 153 * Hence this method will return the first delegate that is not a {@code DelegatingConnection}, or {@code null} when 154 * no non-{@code DelegatingConnection} delegate can be found by traversing this chain. 155 * </p> 156 * <p> 157 * This method is useful when you may have nested {@code DelegatingConnection}s, and you want to make sure to obtain 158 * a "genuine" {@link Connection}. 159 * </p> 160 * 161 * @return innermost delegate. 162 */ 163 public Connection getInnermostDelegate() { 164 return getInnermostDelegateInternal(); 165 } 166 167 /** 168 * Although this method is public, it is part of the internal API and should not be used by clients. The signature 169 * of this method may change at any time including in ways that break backwards compatibility. 170 * 171 * @return innermost delegate. 172 */ 173 @SuppressWarnings("resource") 174 public final Connection getInnermostDelegateInternal() { 175 Connection conn = connection; 176 while (conn != null && conn instanceof DelegatingConnection) { 177 conn = ((DelegatingConnection<?>) conn).getDelegateInternal(); 178 if (this == conn) { 179 return null; 180 } 181 } 182 return conn; 183 } 184 185 /** 186 * Sets my delegate. 187 * 188 * @param connection 189 * my delegate. 190 */ 191 public void setDelegate(final C connection) { 192 this.connection = connection; 193 } 194 195 /** 196 * Closes the underlying connection, and close any Statements that were not explicitly closed. Sub-classes that 197 * override this method must: 198 * <ol> 199 * <li>Call passivate()</li> 200 * <li>Call close (or the equivalent appropriate action) on the wrapped connection</li> 201 * <li>Set _closed to <code>false</code></li> 202 * </ol> 203 */ 204 @Override 205 public void close() throws SQLException { 206 if (!closed) { 207 closeInternal(); 208 } 209 } 210 211 protected boolean isClosedInternal() { 212 return closed; 213 } 214 215 protected void setClosedInternal(final boolean closed) { 216 this.closed = closed; 217 } 218 219 protected final void closeInternal() throws SQLException { 220 try { 221 passivate(); 222 } finally { 223 if (connection != null) { 224 boolean connectionIsClosed; 225 try { 226 connectionIsClosed = connection.isClosed(); 227 } catch (final SQLException e) { 228 // not sure what the state is, so assume the connection is open. 229 connectionIsClosed = false; 230 } 231 try { 232 // DBCP-512: Avoid exceptions when closing a connection in mutli-threaded use case. 233 // Avoid closing again, which should be a no-op, but some drivers like H2 throw an exception when 234 // closing from multiple threads. 235 if (!connectionIsClosed) { 236 connection.close(); 237 } 238 } finally { 239 closed = true; 240 } 241 } else { 242 closed = true; 243 } 244 } 245 } 246 247 protected void handleException(final SQLException e) throws SQLException { 248 throw e; 249 } 250 251 /** 252 * Handles the given {@code SQLException}. 253 * 254 * @param <T> The throwable type. 255 * @param e The SQLException 256 * @return the given {@code SQLException} 257 * @since 2.7.0 258 */ 259 protected <T extends Throwable> T handleExceptionNoThrow(final T e) { 260 return e; 261 } 262 263 private void initializeStatement(final DelegatingStatement ds) throws SQLException { 264 if (defaultQueryTimeoutSeconds != null && defaultQueryTimeoutSeconds.intValue() != ds.getQueryTimeout()) { 265 ds.setQueryTimeout(defaultQueryTimeoutSeconds.intValue()); 266 } 267 } 268 269 @Override 270 public Statement createStatement() throws SQLException { 271 checkOpen(); 272 try { 273 final DelegatingStatement ds = new DelegatingStatement(this, connection.createStatement()); 274 initializeStatement(ds); 275 return ds; 276 } catch (final SQLException e) { 277 handleException(e); 278 return null; 279 } 280 } 281 282 @Override 283 public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { 284 checkOpen(); 285 try { 286 final DelegatingStatement ds = new DelegatingStatement(this, 287 connection.createStatement(resultSetType, resultSetConcurrency)); 288 initializeStatement(ds); 289 return ds; 290 } catch (final SQLException e) { 291 handleException(e); 292 return null; 293 } 294 } 295 296 @Override 297 public PreparedStatement prepareStatement(final String sql) throws SQLException { 298 checkOpen(); 299 try { 300 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 301 connection.prepareStatement(sql)); 302 initializeStatement(dps); 303 return dps; 304 } catch (final SQLException e) { 305 handleException(e); 306 return null; 307 } 308 } 309 310 @Override 311 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) 312 throws SQLException { 313 checkOpen(); 314 try { 315 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 316 connection.prepareStatement(sql, resultSetType, resultSetConcurrency)); 317 initializeStatement(dps); 318 return dps; 319 } catch (final SQLException e) { 320 handleException(e); 321 return null; 322 } 323 } 324 325 @Override 326 public CallableStatement prepareCall(final String sql) throws SQLException { 327 checkOpen(); 328 try { 329 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, connection.prepareCall(sql)); 330 initializeStatement(dcs); 331 return dcs; 332 } catch (final SQLException e) { 333 handleException(e); 334 return null; 335 } 336 } 337 338 @Override 339 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) 340 throws SQLException { 341 checkOpen(); 342 try { 343 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, 344 connection.prepareCall(sql, resultSetType, resultSetConcurrency)); 345 initializeStatement(dcs); 346 return dcs; 347 } catch (final SQLException e) { 348 handleException(e); 349 return null; 350 } 351 } 352 353 @Override 354 public void clearWarnings() throws SQLException { 355 checkOpen(); 356 try { 357 connection.clearWarnings(); 358 } catch (final SQLException e) { 359 handleException(e); 360 } 361 } 362 363 @Override 364 public void commit() throws SQLException { 365 checkOpen(); 366 try { 367 connection.commit(); 368 } catch (final SQLException e) { 369 handleException(e); 370 } 371 } 372 373 /** 374 * Returns the state caching flag. 375 * 376 * @return the state caching flag 377 */ 378 public boolean getCacheState() { 379 return cacheState; 380 } 381 382 @Override 383 public boolean getAutoCommit() throws SQLException { 384 checkOpen(); 385 if (cacheState && autoCommitCached != null) { 386 return autoCommitCached.booleanValue(); 387 } 388 try { 389 autoCommitCached = Boolean.valueOf(connection.getAutoCommit()); 390 return autoCommitCached.booleanValue(); 391 } catch (final SQLException e) { 392 handleException(e); 393 return false; 394 } 395 } 396 397 @Override 398 public String getCatalog() throws SQLException { 399 checkOpen(); 400 try { 401 return connection.getCatalog(); 402 } catch (final SQLException e) { 403 handleException(e); 404 return null; 405 } 406 } 407 408 @Override 409 public DatabaseMetaData getMetaData() throws SQLException { 410 checkOpen(); 411 try { 412 return new DelegatingDatabaseMetaData(this, connection.getMetaData()); 413 } catch (final SQLException e) { 414 handleException(e); 415 return null; 416 } 417 } 418 419 @Override 420 public int getTransactionIsolation() throws SQLException { 421 checkOpen(); 422 try { 423 return connection.getTransactionIsolation(); 424 } catch (final SQLException e) { 425 handleException(e); 426 return -1; 427 } 428 } 429 430 @Override 431 public Map<String, Class<?>> getTypeMap() throws SQLException { 432 checkOpen(); 433 try { 434 return connection.getTypeMap(); 435 } catch (final SQLException e) { 436 handleException(e); 437 return null; 438 } 439 } 440 441 @Override 442 public SQLWarning getWarnings() throws SQLException { 443 checkOpen(); 444 try { 445 return connection.getWarnings(); 446 } catch (final SQLException e) { 447 handleException(e); 448 return null; 449 } 450 } 451 452 @Override 453 public boolean isReadOnly() throws SQLException { 454 checkOpen(); 455 if (cacheState && readOnlyCached != null) { 456 return readOnlyCached.booleanValue(); 457 } 458 try { 459 readOnlyCached = Boolean.valueOf(connection.isReadOnly()); 460 return readOnlyCached.booleanValue(); 461 } catch (final SQLException e) { 462 handleException(e); 463 return false; 464 } 465 } 466 467 @Override 468 public String nativeSQL(final String sql) throws SQLException { 469 checkOpen(); 470 try { 471 return connection.nativeSQL(sql); 472 } catch (final SQLException e) { 473 handleException(e); 474 return null; 475 } 476 } 477 478 @Override 479 public void rollback() throws SQLException { 480 checkOpen(); 481 try { 482 connection.rollback(); 483 } catch (final SQLException e) { 484 handleException(e); 485 } 486 } 487 488 /** 489 * Gets the default query timeout that will be used for {@link Statement}s created from this connection. 490 * <code>null</code> means that the driver default will be used. 491 * 492 * @return query timeout limit in seconds; zero means there is no limit. 493 */ 494 public Integer getDefaultQueryTimeout() { 495 return defaultQueryTimeoutSeconds; 496 } 497 498 /** 499 * Sets the default query timeout that will be used for {@link Statement}s created from this connection. 500 * <code>null</code> means that the driver default will be used. 501 * 502 * @param defaultQueryTimeoutSeconds 503 * the new query timeout limit in seconds; zero means there is no limit 504 */ 505 public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { 506 this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds; 507 } 508 509 /** 510 * Sets the state caching flag. 511 * 512 * @param cacheState 513 * The new value for the state caching flag 514 */ 515 public void setCacheState(final boolean cacheState) { 516 this.cacheState = cacheState; 517 } 518 519 /** 520 * Can be used to clear cached state when it is known that the underlying connection may have been accessed 521 * directly. 522 */ 523 public void clearCachedState() { 524 autoCommitCached = null; 525 readOnlyCached = null; 526 if (connection instanceof DelegatingConnection) { 527 ((DelegatingConnection<?>) connection).clearCachedState(); 528 } 529 } 530 531 @Override 532 public void setAutoCommit(final boolean autoCommit) throws SQLException { 533 checkOpen(); 534 try { 535 connection.setAutoCommit(autoCommit); 536 if (cacheState) { 537 autoCommitCached = Boolean.valueOf(connection.getAutoCommit()); 538 } 539 } catch (final SQLException e) { 540 autoCommitCached = null; 541 handleException(e); 542 } 543 } 544 545 @Override 546 public void setCatalog(final String catalog) throws SQLException { 547 checkOpen(); 548 try { 549 connection.setCatalog(catalog); 550 } catch (final SQLException e) { 551 handleException(e); 552 } 553 } 554 555 @Override 556 public void setReadOnly(final boolean readOnly) throws SQLException { 557 checkOpen(); 558 try { 559 connection.setReadOnly(readOnly); 560 if (cacheState) { 561 readOnlyCached = Boolean.valueOf(connection.isReadOnly()); 562 } 563 } catch (final SQLException e) { 564 readOnlyCached = null; 565 handleException(e); 566 } 567 } 568 569 @Override 570 public void setTransactionIsolation(final int level) throws SQLException { 571 checkOpen(); 572 try { 573 connection.setTransactionIsolation(level); 574 } catch (final SQLException e) { 575 handleException(e); 576 } 577 } 578 579 @Override 580 public void setTypeMap(final Map<String, Class<?>> map) throws SQLException { 581 checkOpen(); 582 try { 583 connection.setTypeMap(map); 584 } catch (final SQLException e) { 585 handleException(e); 586 } 587 } 588 589 @Override 590 public boolean isClosed() throws SQLException { 591 return closed || connection == null || connection.isClosed(); 592 } 593 594 protected void checkOpen() throws SQLException { 595 if (closed) { 596 if (null != connection) { 597 String label = ""; 598 try { 599 label = connection.toString(); 600 } catch (final Exception ex) { 601 // ignore, leave label empty 602 } 603 throw new SQLException("Connection " + label + " is closed."); 604 } 605 throw new SQLException("Connection is null."); 606 } 607 } 608 609 protected void activate() { 610 closed = false; 611 setLastUsed(); 612 if (connection instanceof DelegatingConnection) { 613 ((DelegatingConnection<?>) connection).activate(); 614 } 615 } 616 617 protected void passivate() throws SQLException { 618 // The JDBC specification requires that a Connection close any open 619 // Statement's when it is closed. 620 // DBCP-288. Not all the traced objects will be statements 621 final List<AbandonedTrace> traces = getTrace(); 622 if (traces != null && !traces.isEmpty()) { 623 final List<Exception> thrownList = new ArrayList<>(); 624 final Iterator<AbandonedTrace> traceIter = traces.iterator(); 625 while (traceIter.hasNext()) { 626 final Object trace = traceIter.next(); 627 if (trace instanceof Statement) { 628 try { 629 ((Statement) trace).close(); 630 } catch (Exception e) { 631 thrownList.add(e); 632 } 633 } else if (trace instanceof ResultSet) { 634 // DBCP-265: Need to close the result sets that are 635 // generated via DatabaseMetaData 636 try { 637 ((ResultSet) trace).close(); 638 } catch (Exception e) { 639 thrownList.add(e); 640 } 641 } 642 } 643 clearTrace(); 644 if (!thrownList.isEmpty()) { 645 throw new SQLExceptionList(thrownList); 646 } 647 } 648 setLastUsed(0); 649 } 650 651 @Override 652 public int getHoldability() throws SQLException { 653 checkOpen(); 654 try { 655 return connection.getHoldability(); 656 } catch (final SQLException e) { 657 handleException(e); 658 return 0; 659 } 660 } 661 662 @Override 663 public void setHoldability(final int holdability) throws SQLException { 664 checkOpen(); 665 try { 666 connection.setHoldability(holdability); 667 } catch (final SQLException e) { 668 handleException(e); 669 } 670 } 671 672 @Override 673 public Savepoint setSavepoint() throws SQLException { 674 checkOpen(); 675 try { 676 return connection.setSavepoint(); 677 } catch (final SQLException e) { 678 handleException(e); 679 return null; 680 } 681 } 682 683 @Override 684 public Savepoint setSavepoint(final String name) throws SQLException { 685 checkOpen(); 686 try { 687 return connection.setSavepoint(name); 688 } catch (final SQLException e) { 689 handleException(e); 690 return null; 691 } 692 } 693 694 @Override 695 public void rollback(final Savepoint savepoint) throws SQLException { 696 checkOpen(); 697 try { 698 connection.rollback(savepoint); 699 } catch (final SQLException e) { 700 handleException(e); 701 } 702 } 703 704 @Override 705 public void releaseSavepoint(final Savepoint savepoint) throws SQLException { 706 checkOpen(); 707 try { 708 connection.releaseSavepoint(savepoint); 709 } catch (final SQLException e) { 710 handleException(e); 711 } 712 } 713 714 @Override 715 public Statement createStatement(final int resultSetType, final int resultSetConcurrency, 716 final int resultSetHoldability) throws SQLException { 717 checkOpen(); 718 try { 719 final DelegatingStatement ds = new DelegatingStatement(this, 720 connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)); 721 initializeStatement(ds); 722 return ds; 723 } catch (final SQLException e) { 724 handleException(e); 725 return null; 726 } 727 } 728 729 @Override 730 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, 731 final int resultSetHoldability) throws SQLException { 732 checkOpen(); 733 try { 734 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 735 connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 736 initializeStatement(dps); 737 return dps; 738 } catch (final SQLException e) { 739 handleException(e); 740 return null; 741 } 742 } 743 744 @Override 745 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, 746 final int resultSetHoldability) throws SQLException { 747 checkOpen(); 748 try { 749 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, 750 connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 751 initializeStatement(dcs); 752 return dcs; 753 } catch (final SQLException e) { 754 handleException(e); 755 return null; 756 } 757 } 758 759 @Override 760 public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { 761 checkOpen(); 762 try { 763 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 764 connection.prepareStatement(sql, autoGeneratedKeys)); 765 initializeStatement(dps); 766 return dps; 767 } catch (final SQLException e) { 768 handleException(e); 769 return null; 770 } 771 } 772 773 @Override 774 public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException { 775 checkOpen(); 776 try { 777 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 778 connection.prepareStatement(sql, columnIndexes)); 779 initializeStatement(dps); 780 return dps; 781 } catch (final SQLException e) { 782 handleException(e); 783 return null; 784 } 785 } 786 787 @Override 788 public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException { 789 checkOpen(); 790 try { 791 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 792 connection.prepareStatement(sql, columnNames)); 793 initializeStatement(dps); 794 return dps; 795 } catch (final SQLException e) { 796 handleException(e); 797 return null; 798 } 799 } 800 801 @Override 802 public boolean isWrapperFor(final Class<?> iface) throws SQLException { 803 if (iface.isAssignableFrom(getClass())) { 804 return true; 805 } else if (iface.isAssignableFrom(connection.getClass())) { 806 return true; 807 } else { 808 return connection.isWrapperFor(iface); 809 } 810 } 811 812 @Override 813 public <T> T unwrap(final Class<T> iface) throws SQLException { 814 if (iface.isAssignableFrom(getClass())) { 815 return iface.cast(this); 816 } else if (iface.isAssignableFrom(connection.getClass())) { 817 return iface.cast(connection); 818 } else { 819 return connection.unwrap(iface); 820 } 821 } 822 823 @Override 824 public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { 825 checkOpen(); 826 try { 827 return connection.createArrayOf(typeName, elements); 828 } catch (final SQLException e) { 829 handleException(e); 830 return null; 831 } 832 } 833 834 @Override 835 public Blob createBlob() throws SQLException { 836 checkOpen(); 837 try { 838 return connection.createBlob(); 839 } catch (final SQLException e) { 840 handleException(e); 841 return null; 842 } 843 } 844 845 @Override 846 public Clob createClob() throws SQLException { 847 checkOpen(); 848 try { 849 return connection.createClob(); 850 } catch (final SQLException e) { 851 handleException(e); 852 return null; 853 } 854 } 855 856 @Override 857 public NClob createNClob() throws SQLException { 858 checkOpen(); 859 try { 860 return connection.createNClob(); 861 } catch (final SQLException e) { 862 handleException(e); 863 return null; 864 } 865 } 866 867 @Override 868 public SQLXML createSQLXML() throws SQLException { 869 checkOpen(); 870 try { 871 return connection.createSQLXML(); 872 } catch (final SQLException e) { 873 handleException(e); 874 return null; 875 } 876 } 877 878 @Override 879 public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { 880 checkOpen(); 881 try { 882 return connection.createStruct(typeName, attributes); 883 } catch (final SQLException e) { 884 handleException(e); 885 return null; 886 } 887 } 888 889 @Override 890 public boolean isValid(final int timeoutSeconds) throws SQLException { 891 if (isClosed()) { 892 return false; 893 } 894 try { 895 return connection.isValid(timeoutSeconds); 896 } catch (final SQLException e) { 897 handleException(e); 898 return false; 899 } 900 } 901 902 @Override 903 public void setClientInfo(final String name, final String value) throws SQLClientInfoException { 904 try { 905 checkOpen(); 906 connection.setClientInfo(name, value); 907 } catch (final SQLClientInfoException e) { 908 throw e; 909 } catch (final SQLException e) { 910 throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e); 911 } 912 } 913 914 @Override 915 public void setClientInfo(final Properties properties) throws SQLClientInfoException { 916 try { 917 checkOpen(); 918 connection.setClientInfo(properties); 919 } catch (final SQLClientInfoException e) { 920 throw e; 921 } catch (final SQLException e) { 922 throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e); 923 } 924 } 925 926 @Override 927 public Properties getClientInfo() throws SQLException { 928 checkOpen(); 929 try { 930 return connection.getClientInfo(); 931 } catch (final SQLException e) { 932 handleException(e); 933 return null; 934 } 935 } 936 937 @Override 938 public String getClientInfo(final String name) throws SQLException { 939 checkOpen(); 940 try { 941 return connection.getClientInfo(name); 942 } catch (final SQLException e) { 943 handleException(e); 944 return null; 945 } 946 } 947 948 @Override 949 public void setSchema(final String schema) throws SQLException { 950 checkOpen(); 951 try { 952 Jdbc41Bridge.setSchema(connection, schema); 953 } catch (final SQLException e) { 954 handleException(e); 955 } 956 } 957 958 @Override 959 public String getSchema() throws SQLException { 960 checkOpen(); 961 try { 962 return Jdbc41Bridge.getSchema(connection); 963 } catch (final SQLException e) { 964 handleException(e); 965 return null; 966 } 967 } 968 969 @Override 970 public void abort(final Executor executor) throws SQLException { 971 checkOpen(); 972 try { 973 Jdbc41Bridge.abort(connection, executor); 974 } catch (final SQLException e) { 975 handleException(e); 976 } 977 } 978 979 @Override 980 public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { 981 checkOpen(); 982 try { 983 Jdbc41Bridge.setNetworkTimeout(connection, executor, milliseconds); 984 } catch (final SQLException e) { 985 handleException(e); 986 } 987 } 988 989 @Override 990 public int getNetworkTimeout() throws SQLException { 991 checkOpen(); 992 try { 993 return Jdbc41Bridge.getNetworkTimeout(connection); 994 } catch (final SQLException e) { 995 handleException(e); 996 return 0; 997 } 998 } 999}