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