/* * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 2.0, as published by the * Free Software Foundation. * * This program is also distributed with certain software (including but not * limited to OpenSSL) that is licensed under separate terms, as designated in a * particular file or component or in included license documentation. The * authors of MySQL hereby grant you an additional permission to link the * program and your derivative works with the separately licensed software that * they have included with MySQL. * * Without limiting anything contained in the foregoing, this file, which is * part of MySQL Connector/J, is also subject to the Universal FOSS Exception, * version 1.0, a copy of which can be found at * http://oss.oracle.com/licenses/universal-foss-exception. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, * for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.mysql.cj.jdbc; import java.io.Serializable; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationHandler; import java.sql.Blob; import java.sql.Clob; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.NClob; import java.sql.ResultSet; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLPermission; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Struct; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.Stack; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.stream.Collectors; import com.mysql.cj.CacheAdapter; import com.mysql.cj.CacheAdapterFactory; import com.mysql.cj.Constants; import com.mysql.cj.LicenseConfiguration; import com.mysql.cj.Messages; import com.mysql.cj.NativeSession; import com.mysql.cj.NoSubInterceptorWrapper; import com.mysql.cj.ParseInfo; import com.mysql.cj.PreparedQuery; import com.mysql.cj.ServerVersion; import com.mysql.cj.Session.SessionEventListener; import com.mysql.cj.conf.HostInfo; import com.mysql.cj.conf.ModifiableProperty; import com.mysql.cj.conf.PropertyDefinitions; import com.mysql.cj.conf.ReadableProperty; import com.mysql.cj.exceptions.CJException; import com.mysql.cj.exceptions.ExceptionFactory; import com.mysql.cj.exceptions.ExceptionInterceptor; import com.mysql.cj.exceptions.ExceptionInterceptorChain; import com.mysql.cj.exceptions.MysqlErrorNumbers; import com.mysql.cj.exceptions.PasswordExpiredException; import com.mysql.cj.exceptions.UnableToConnectException; import com.mysql.cj.interceptors.QueryInterceptor; import com.mysql.cj.jdbc.exceptions.CommunicationsException; import com.mysql.cj.jdbc.exceptions.SQLError; import com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping; import com.mysql.cj.jdbc.ha.MultiHostMySQLConnection; import com.mysql.cj.jdbc.interceptors.ConnectionLifecycleInterceptor; import com.mysql.cj.jdbc.result.CachedResultSetMetaData; import com.mysql.cj.jdbc.result.CachedResultSetMetaDataImpl; import com.mysql.cj.jdbc.result.ResultSetFactory; import com.mysql.cj.jdbc.result.ResultSetInternalMethods; import com.mysql.cj.jdbc.result.UpdatableResultSet; import com.mysql.cj.log.ProfilerEvent; import com.mysql.cj.log.ProfilerEventHandlerFactory; import com.mysql.cj.log.ProfilerEventImpl; import com.mysql.cj.log.StandardLogger; import com.mysql.cj.protocol.SocksProxySocketFactory; import com.mysql.cj.util.LRUCache; import com.mysql.cj.util.LogUtils; import com.mysql.cj.util.StringUtils; import com.mysql.cj.util.Util; /** * A Connection represents a session with a specific database. Within the context of a Connection, SQL statements are executed and results are returned. * *
* A Connection's database is able to provide information describing its tables, its supported SQL grammar, its stored procedures, the capabilities of this * connection, etc. This information is obtained with the getMetaData method. *
*/ public class ConnectionImpl implements JdbcConnection, SessionEventListener, Serializable { private static final long serialVersionUID = 4009476458425101761L; private static final SQLPermission SET_NETWORK_TIMEOUT_PERM = new SQLPermission("setNetworkTimeout"); private static final SQLPermission ABORT_PERM = new SQLPermission("abort"); public String getHost() { return this.session.getHostInfo().getHost(); } private JdbcConnection proxy = null; private InvocationHandler realProxy = null; public boolean isProxySet() { return this.proxy != null; } public void setProxy(JdbcConnection proxy) { this.proxy = proxy; this.realProxy = this.proxy instanceof MultiHostMySQLConnection ? ((MultiHostMySQLConnection) proxy).getThisAsProxy() : null; } // this connection has to be proxied when using multi-host settings so that statements get routed to the right physical connection // (works as "logical" connection) private JdbcConnection getProxy() { return (this.proxy != null) ? this.proxy : (JdbcConnection) this; } public JdbcConnection getMultiHostSafeProxy() { return this.getProxy(); } public JdbcConnection getActiveMySQLConnection() { return this; } public Object getConnectionMutex() { return (this.realProxy != null) ? this.realProxy : getProxy(); } /** * Used as a key for caching callable statements which (may) depend on * current catalog...In 5.0.x, they don't (currently), but stored procedure * names soon will, so current catalog is a (hidden) component of the name. */ static class CompoundCacheKey { final String componentOne; final String componentTwo; final int hashCode; CompoundCacheKey(String partOne, String partTwo) { this.componentOne = partOne; this.componentTwo = partTwo; int hc = 17; hc = 31 * hc + (this.componentOne != null ? this.componentOne.hashCode() : 0); hc = 31 * hc + (this.componentTwo != null ? this.componentTwo.hashCode() : 0); this.hashCode = hc; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj != null && CompoundCacheKey.class.isAssignableFrom(obj.getClass())) { CompoundCacheKey another = (CompoundCacheKey) obj; if (this.componentOne == null ? another.componentOne == null : this.componentOne.equals(another.componentOne)) { return this.componentTwo == null ? another.componentTwo == null : this.componentTwo.equals(another.componentTwo); } } return false; } @Override public int hashCode() { return this.hashCode; } } /** * The mapping between MySQL charset names and Java charset names. * Initialized by loadCharacterSetMapping() */ public static Map, ?> charsetMap; /** Default logger class name */ protected static final String DEFAULT_LOGGER_CLASS = StandardLogger.class.getName(); /** * Map mysql transaction isolation level name to * java.sql.Connection.TRANSACTION_XXX */ private static Map* Note: MySQL does not support transactions, so this method is a no-op. *
* * @exception SQLException * if a database access error occurs * @see setAutoCommit */ public void commit() throws SQLException { synchronized (getConnectionMutex()) { checkClosed(); try { if (this.connectionLifecycleInterceptors != null) { IterateBlock* Note: MySQL's notion of catalogs are individual databases. *
* * @return the current catalog name or null * @exception SQLException * if a database access error occurs */ public String getCatalog() throws SQLException { synchronized (getConnectionMutex()) { return this.database; } } /** * @return Returns the characterSetMetadata. */ public String getCharacterSetMetadata() { synchronized (getConnectionMutex()) { return this.session.getServerSession().getCharacterSetMetadata(); } } public int getHoldability() throws SQLException { return java.sql.ResultSet.CLOSE_CURSORS_AT_COMMIT; } public long getId() { return this.session.getThreadId(); } /** * NOT JDBC-Compliant, but clients can use this method to determine how long * this connection has been idle. This time (reported in milliseconds) is * updated once a query has completed. * * @return number of ms that this connection has been idle, 0 if the driver * is busy retrieving results. */ public long getIdleFor() { synchronized (getConnectionMutex()) { return this.session.getIdleFor(); } } /** * A connection's database is able to provide information describing its * tables, its supported SQL grammar, its stored procedures, the * capabilities of this connection, etc. This information is made available * through a DatabaseMetaData object. * * @return a DatabaseMetaData object for this connection * @exception SQLException * if a database access error occurs */ public java.sql.DatabaseMetaData getMetaData() throws SQLException { return getMetaData(true, true); } private java.sql.DatabaseMetaData getMetaData(boolean checkClosed, boolean checkForInfoSchema) throws SQLException { if (checkClosed) { checkClosed(); } com.mysql.cj.jdbc.DatabaseMetaData dbmeta = com.mysql.cj.jdbc.DatabaseMetaData.getInstance(getMultiHostSafeProxy(), this.database, checkForInfoSchema, this.nullStatementResultSetFactory); if (getSession() != null && getSession().getProtocol() != null) { dbmeta.setMetadataEncoding(getSession().getServerSession().getCharacterSetMetadata()); dbmeta.setMetadataCollationIndex(getSession().getServerSession().getMetadataCollationIndex()); } return dbmeta; } public java.sql.Statement getMetadataSafeStatement() throws SQLException { return getMetadataSafeStatement(0); } public java.sql.Statement getMetadataSafeStatement(int maxRows) throws SQLException { java.sql.Statement stmt = createStatement(); stmt.setMaxRows(maxRows == -1 ? 0 : maxRows); stmt.setEscapeProcessing(false); if (stmt.getFetchSize() != 0) { stmt.setFetchSize(0); } return stmt; } public ServerVersion getServerVersion() { return this.session.getServerSession().getServerVersion(); } /** * Get this Connection's current transaction isolation mode. * * @return the current TRANSACTION_ mode value * @exception SQLException * if a database access error occurs */ public int getTransactionIsolation() throws SQLException { synchronized (getConnectionMutex()) { if (!this.useLocalSessionState.getValue()) { String s = this.session.queryServerVariable(versionMeetsMinimum(8, 0, 3) || (versionMeetsMinimum(5, 7, 20) && !versionMeetsMinimum(8, 0, 0)) ? "@@session.transaction_isolation" : "@@session.tx_isolation"); if (s != null) { Integer intTI = mapTransIsolationNameToValue.get(s); if (intTI != null) { this.isolationLevel = intTI.intValue(); return this.isolationLevel; } throw SQLError.createSQLException(Messages.getString("Connection.12", new Object[] { s }), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor()); } throw SQLError.createSQLException(Messages.getString("Connection.13"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor()); } return this.isolationLevel; } } /** * JDBC 2.0 Get the type-map object associated with this connection. By * default, the map returned is empty. * * @return the type map * @throws SQLException * if a database error occurs */ public java.util.Map* Note: This method is optimized for handling parametric SQL statements that benefit from precompilation if the driver supports precompilation. In * this case, the statement is not sent to the database until the PreparedStatement is executed. This has no direct effect on users; however it does affect * which method throws certain java.sql.SQLExceptions *
** MySQL does not support precompilation of statements, so they are handled by the driver. *
* * @param sql * a SQL statement that may contain one or more '?' IN parameter * placeholders * @return a new PreparedStatement object containing the pre-compiled * statement. * @exception SQLException * if a database access error occurs. */ public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException { return prepareStatement(sql, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY); } public java.sql.PreparedStatement prepareStatement(String sql, int autoGenKeyIndex) throws SQLException { java.sql.PreparedStatement pStmt = prepareStatement(sql); ((ClientPreparedStatement) pStmt).setRetrieveGeneratedKeys(autoGenKeyIndex == java.sql.Statement.RETURN_GENERATED_KEYS); return pStmt; } /** * JDBC 2.0 Same as prepareStatement() above, but allows the default result * set type and result set concurrency type to be overridden. * * @param sql * the SQL query containing place holders * @param resultSetType * a result set type, see ResultSet.TYPE_XXX * @param resultSetConcurrency * a concurrency type, see ResultSet.CONCUR_XXX * @return a new PreparedStatement object containing the pre-compiled SQL * statement * @exception SQLException * if a database-access error occurs. */ public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { synchronized (getConnectionMutex()) { checkClosed(); // // FIXME: Create warnings if can't create results of the given type or concurrency // ClientPreparedStatement pStmt = null; boolean canServerPrepare = true; String nativeSql = this.processEscapeCodesForPrepStmts.getValue() ? nativeSQL(sql) : sql; if (this.useServerPrepStmts.getValue() && this.emulateUnsupportedPstmts.getValue()) { canServerPrepare = canHandleAsServerPreparedStatement(nativeSql); } if (this.useServerPrepStmts.getValue() && canServerPrepare) { if (this.cachePrepStmts.getValue()) { synchronized (this.serverSideStatementCache) { pStmt = this.serverSideStatementCache.remove(new CompoundCacheKey(this.database, sql)); if (pStmt != null) { ((com.mysql.cj.jdbc.ServerPreparedStatement) pStmt).setClosed(false); pStmt.clearParameters(); } if (pStmt == null) { try { pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType, resultSetConcurrency); if (sql.length() < this.prepStmtCacheSqlLimit.getValue()) { ((com.mysql.cj.jdbc.ServerPreparedStatement) pStmt).isCached = true; } pStmt.setResultSetType(resultSetType); pStmt.setResultSetConcurrency(resultSetConcurrency); } catch (SQLException sqlEx) { // Punt, if necessary if (this.emulateUnsupportedPstmts.getValue()) { pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false); if (sql.length() < this.prepStmtCacheSqlLimit.getValue()) { this.serverSideStatementCheckCache.put(sql, Boolean.FALSE); } } else { throw sqlEx; } } } } } else { try { pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType, resultSetConcurrency); pStmt.setResultSetType(resultSetType); pStmt.setResultSetConcurrency(resultSetConcurrency); } catch (SQLException sqlEx) { // Punt, if necessary if (this.emulateUnsupportedPstmts.getValue()) { pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false); } else { throw sqlEx; } } } } else { pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false); } return pStmt; } } public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { if (this.pedantic.getValue()) { if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) { throw SQLError.createSQLException(Messages.getString("Connection.17"), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } } return prepareStatement(sql, resultSetType, resultSetConcurrency); } public java.sql.PreparedStatement prepareStatement(String sql, int[] autoGenKeyIndexes) throws SQLException { java.sql.PreparedStatement pStmt = prepareStatement(sql); ((ClientPreparedStatement) pStmt).setRetrieveGeneratedKeys((autoGenKeyIndexes != null) && (autoGenKeyIndexes.length > 0)); return pStmt; } public java.sql.PreparedStatement prepareStatement(String sql, String[] autoGenKeyColNames) throws SQLException { java.sql.PreparedStatement pStmt = prepareStatement(sql); ((ClientPreparedStatement) pStmt).setRetrieveGeneratedKeys((autoGenKeyColNames != null) && (autoGenKeyColNames.length > 0)); return pStmt; } /** * Closes connection and frees resources. * * @param calledExplicitly * is this being called from close() * @param issueRollback * should a rollback() be issued? * @throws SQLException * if an error occurs */ public void realClose(boolean calledExplicitly, boolean issueRollback, boolean skipLocalTeardown, Throwable reason) throws SQLException { SQLException sqlEx = null; if (this.isClosed()) { return; } this.session.setForceClosedReason(reason); try { if (!skipLocalTeardown) { if (!getAutoCommit() && issueRollback) { try { rollback(); } catch (SQLException ex) { sqlEx = ex; } } this.session.reportMetrics(); if (this.useUsageAdvisor.getValue()) { if (!calledExplicitly) { this.session.getProfilerEventHandler() .consumeEvent(new ProfilerEventImpl(ProfilerEvent.TYPE_WARN, "", this.getCatalog(), this.session.getThreadId(), -1, -1, System.currentTimeMillis(), 0, Constants.MILLIS_I18N, null, this.pointOfOrigin, Messages.getString("Connection.18"))); } long connectionLifeTime = System.currentTimeMillis() - this.session.getConnectionCreationTimeMillis(); if (connectionLifeTime < 500) { this.session.getProfilerEventHandler() .consumeEvent(new ProfilerEventImpl(ProfilerEvent.TYPE_WARN, "", this.getCatalog(), this.session.getThreadId(), -1, -1, System.currentTimeMillis(), 0, Constants.MILLIS_I18N, null, this.pointOfOrigin, Messages.getString("Connection.19"))); } } try { closeAllOpenStatements(); } catch (SQLException ex) { sqlEx = ex; } this.session.quit(); } else { this.session.forceClose(); } if (this.queryInterceptors != null) { for (int i = 0; i < this.queryInterceptors.size(); i++) { this.queryInterceptors.get(i).destroy(); } } if (this.exceptionInterceptor != null) { this.exceptionInterceptor.destroy(); } } finally { ProfilerEventHandlerFactory.removeInstance(this.session); this.openStatements.clear(); this.queryInterceptors = null; this.exceptionInterceptor = null; this.nullStatementResultSetFactory = null; } if (sqlEx != null) { throw sqlEx; } } public void recachePreparedStatement(JdbcPreparedStatement pstmt) throws SQLException { synchronized (getConnectionMutex()) { if (this.cachePrepStmts.getValue() && pstmt.isPoolable()) { synchronized (this.serverSideStatementCache) { Object oldServerPrepStmt = this.serverSideStatementCache.put( new CompoundCacheKey(pstmt.getCurrentCatalog(), ((PreparedQuery>) pstmt.getQuery()).getOriginalSql()), (ServerPreparedStatement) pstmt); if (oldServerPrepStmt != null && oldServerPrepStmt != pstmt) { ((ServerPreparedStatement) oldServerPrepStmt).isCached = false; ((ServerPreparedStatement) oldServerPrepStmt).setClosed(false); ((ServerPreparedStatement) oldServerPrepStmt).realClose(true, true); } } } } } public void decachePreparedStatement(JdbcPreparedStatement pstmt) throws SQLException { synchronized (getConnectionMutex()) { if (this.cachePrepStmts.getValue() && pstmt.isPoolable()) { synchronized (this.serverSideStatementCache) { this.serverSideStatementCache .remove(new CompoundCacheKey(pstmt.getCurrentCatalog(), ((PreparedQuery>) pstmt.getQuery()).getOriginalSql())); } } } } /** * Register a Statement instance as open. * * @param stmt * the Statement instance to remove */ public void registerStatement(JdbcStatement stmt) { this.openStatements.addIfAbsent(stmt); } public void releaseSavepoint(Savepoint arg0) throws SQLException { // this is a no-op } /** * Resets the server-side state of this connection. Doesn't work if isParanoid() is set (it will become a * no-op in this case). Usually only used from connection pooling code. * * @throws SQLException * if the operation fails while resetting server state. */ public void resetServerState() throws SQLException { if (!this.propertySet.getBooleanReadableProperty(PropertyDefinitions.PNAME_paranoid).getValue() && (this.session != null)) { changeUser(this.user, this.password); } } /** * The method rollback() drops all changes made since the previous * commit/rollback and releases any database locks currently held by the * Connection. * * @exception SQLException * if a database access error occurs * @see commit */ public void rollback() throws SQLException { synchronized (getConnectionMutex()) { checkClosed(); try { if (this.connectionLifecycleInterceptors != null) { IterateBlock* Note: MySQL's notion of catalogs are individual databases. *
* * @param catalog * the database for this connection to use * @throws SQLException * if a database access error occurs */ public void setCatalog(final String catalog) throws SQLException { synchronized (getConnectionMutex()) { checkClosed(); if (catalog == null) { throw SQLError.createSQLException("Catalog can not be null", MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor()); } if (this.connectionLifecycleInterceptors != null) { IterateBlockabort
results in:
* SQLException
.
*
* Calling abort
marks the connection closed and releases any resources. Calling abort
on a closed connection is a no-op.
*
* It is possible that the aborting and releasing of the resources that are held by the connection can take an extended period of time. When the
* abort
method returns, the connection will have been marked as closed and the Executor
that was passed as a parameter to abort
* may still be executing tasks to release resources.
*
* This method checks to see that there is an
* The query submitted by the driver to validate the connection shall be executed in the context of the current transaction.
*
* @param timeout
* - The time in seconds to wait for the database operation
* used to validate the connection to complete. If
* the timeout period expires before the operation
* completes, this method returns false. A value of
* 0 indicates a timeout is not applied to the
* database operation.
*
* @return true if the connection is valid, false otherwise
* @exception SQLException
* if the value supplied for SQLPermission
object before allowing the method to proceed. If a SecurityManager
* exists and its checkPermission
method denies calling abort
, this method throws a java.lang.SecurityException
.
*
* @param executor
* The Executor
implementation which will
* be used by abort
.
* @throws java.sql.SQLException
* if a database access error occurs or
* the {@code executor} is {@code null},
* @throws java.lang.SecurityException
* if a security manager exists and its checkPermission
method denies calling abort
* @see SecurityManager#checkPermission
* @see Executor
* @since 1.7
*/
public void abort(Executor executor) throws SQLException {
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkPermission(ABORT_PERM);
}
if (executor == null) {
throw SQLError.createSQLException(Messages.getString("Connection.26"), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
executor.execute(new Runnable() {
public void run() {
try {
abortInternal();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
});
}
public void setNetworkTimeout(Executor executor, final int milliseconds) throws SQLException {
synchronized (getConnectionMutex()) {
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkPermission(SET_NETWORK_TIMEOUT_PERM);
}
if (executor == null) {
throw SQLError.createSQLException(Messages.getString("Connection.26"), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
checkClosed();
executor.execute(new NetworkTimeoutSetter(this, milliseconds));
}
}
private static class NetworkTimeoutSetter implements Runnable {
private final WeakReferencetimeout
is less then 0
* @since 1.6
*/
public boolean isValid(int timeout) throws SQLException {
synchronized (getConnectionMutex()) {
if (isClosed()) {
return false;
}
try {
try {
pingInternal(false, timeout * 1000);
} catch (Throwable t) {
try {
abortInternal();
} catch (Throwable ignoreThrown) {
// we're dead now anyway
}
return false;
}
} catch (Throwable t) {
return false;
}
return true;
}
}
private ClientInfoProvider infoProvider;
public ClientInfoProvider getClientInfoProviderImpl() throws SQLException {
synchronized (getConnectionMutex()) {
if (this.infoProvider == null) {
String clientInfoProvider = this.propertySet.getStringReadableProperty(PropertyDefinitions.PNAME_clientInfoProvider).getStringValue();
try {
try {
this.infoProvider = (ClientInfoProvider) Util.getInstance(clientInfoProvider, new Class>[0], new Object[0],
getExceptionInterceptor());
} catch (CJException ex) {
if (ex.getCause() instanceof ClassCastException) {
// try with package name prepended
try {
this.infoProvider = (ClientInfoProvider) Util.getInstance("com.mysql.cj.jdbc." + clientInfoProvider, new Class>[0],
new Object[0], getExceptionInterceptor());
} catch (CJException e) {
throw SQLExceptionsMapping.translateException(e, getExceptionInterceptor());
}
}
}
} catch (ClassCastException cce) {
throw SQLError.createSQLException(Messages.getString("Connection.ClientInfoNotImplemented", new Object[] { clientInfoProvider }),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
this.infoProvider.initialize(this, this.props);
}
return this.infoProvider;
}
}
public void setClientInfo(String name, String value) throws SQLClientInfoException {
try {
getClientInfoProviderImpl().setClientInfo(this, name, value);
} catch (SQLClientInfoException ciEx) {
throw ciEx;
} catch (SQLException | CJException sqlEx) {
SQLClientInfoException clientInfoEx = new SQLClientInfoException();
clientInfoEx.initCause(sqlEx);
throw clientInfoEx;
}
}
public void setClientInfo(Properties properties) throws SQLClientInfoException {
try {
getClientInfoProviderImpl().setClientInfo(this, properties);
} catch (SQLClientInfoException ciEx) {
throw ciEx;
} catch (SQLException | CJException sqlEx) {
SQLClientInfoException clientInfoEx = new SQLClientInfoException();
clientInfoEx.initCause(sqlEx);
throw clientInfoEx;
}
}
public String getClientInfo(String name) throws SQLException {
return getClientInfoProviderImpl().getClientInfo(this, name);
}
public Properties getClientInfo() throws SQLException {
return getClientInfoProviderImpl().getClientInfo(this);
}
public java.sql.Array createArrayOf(String typeName, Object[] elements) throws SQLException {
throw SQLError.createSQLFeatureNotSupportedException();
}
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
throw SQLError.createSQLFeatureNotSupportedException();
}
/**
* Returns an object that implements the given interface to allow access to non-standard methods,
* or standard methods not exposed by the proxy.
* The result may be either the object found to implement the interface or a proxy for that object.
* If the receiver implements the interface then that is the object. If the receiver is a wrapper
* and the wrapped object implements the interface then that is the object. Otherwise the object is
* the result of calling unwrap
recursively on the wrapped object. If the receiver is not a
* wrapper and does not implement the interface, then an SQLException
is thrown.
*
* @param iface
* A Class defining an interface that the result must implement.
* @return an object that implements the interface. May be a proxy for the actual implementing object.
* @throws java.sql.SQLException
* If no object found that implements the interface
* @since 1.6
*/
public isWrapperFor
on the wrapped
* object. If this does not implement the interface and is not a wrapper, return false.
* This method should be implemented as a low-cost operation compared to unwrap
so that
* callers can use this method to avoid expensive unwrap
calls that may fail. If this method
* returns true then calling unwrap
with the same argument should succeed.
*
* @param interfaces
* a Class defining an interface.
* @return true if this implements the interface or directly or indirectly wraps an object that does.
* @throws java.sql.SQLException
* if an error occurs while determining whether this is a wrapper
* for an object with the given interface.
* @since 1.6
*/
public boolean isWrapperFor(Class> iface) throws SQLException {
// This works for classes that aren't actually wrapping
// anything
return iface.isInstance(this);
}
@Override
public NativeSession getSession() {
return this.session;
}
@Override
public String getHostPortPair() {
return this.origHostInfo.getHostPortPair();
}
@Override
public void handleNormalClose() {
try {
close();
} catch (SQLException e) {
ExceptionFactory.createException(e.getMessage(), e);
}
}
@Override
public void handleReconnect() {
createNewIO(true);
}
@Override
public void handleCleanup(Throwable whyCleanedUp) {
cleanup(whyCleanedUp);
}
}