com.mysql.jdbc.ConnectionImpl Maven / Gradle / Ivy
/*
Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
, like most MySQL Connectors.
There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
this software, see the FLOSS License Exception
.
This program is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation; version 2
of the License.
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 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.jdbc;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.sql.Blob;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLPermission;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Stack;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TreeMap;
import java.util.concurrent.Executor;
import com.mysql.jdbc.PreparedStatement.ParseInfo;
import com.mysql.jdbc.log.Log;
import com.mysql.jdbc.log.LogFactory;
import com.mysql.jdbc.log.LogUtils;
import com.mysql.jdbc.log.NullLogger;
import com.mysql.jdbc.profiler.ProfilerEvent;
import com.mysql.jdbc.profiler.ProfilerEventHandler;
import com.mysql.jdbc.util.LRUCache;
/**
* 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 extends ConnectionPropertiesImpl implements MySQLConnection {
private static final long serialVersionUID = 2877471301981509474L;
private static final SQLPermission SET_NETWORK_TIMEOUT_PERM = new SQLPermission("setNetworkTimeout");
private static final SQLPermission ABORT_PERM = new SQLPermission("abort");
static final String JDBC_LOCAL_CHARACTER_SET_RESULTS = "jdbc.local.character_set_results";
public String getHost() {
return this.host;
}
private MySQLConnection proxy = null;
private InvocationHandler realProxy = null;
public boolean isProxySet() {
return this.proxy != null;
}
public void setProxy(MySQLConnection proxy) {
this.proxy = proxy;
}
public void setRealProxy(InvocationHandler proxy) {
this.realProxy = proxy;
}
// We have to proxy ourselves when we're load balanced so that statements get routed to the right physical connection
// (when load balanced, we're a "logical" connection)
private MySQLConnection getProxy() {
return (this.proxy != null) ? this.proxy : (MySQLConnection) this;
}
public MySQLConnection getLoadBalanceSafeProxy() {
return this.getProxy();
}
public Object getConnectionMutex() {
return (this.realProxy != null) ? this.realProxy : this;
}
class ExceptionInterceptorChain implements ExceptionInterceptor {
List interceptors;
ExceptionInterceptorChain(String interceptorClasses) throws SQLException {
this.interceptors = Util.loadExtensions(ConnectionImpl.this, ConnectionImpl.this.props, interceptorClasses, "Connection.BadExceptionInterceptor",
this);
}
void addRingZero(ExceptionInterceptor interceptor) throws SQLException {
this.interceptors.add(0, interceptor);
}
public SQLException interceptException(SQLException sqlEx, Connection conn) {
if (this.interceptors != null) {
Iterator iter = this.interceptors.iterator();
while (iter.hasNext()) {
sqlEx = ((ExceptionInterceptor) iter.next()).interceptException(sqlEx, ConnectionImpl.this);
}
}
return sqlEx;
}
public void destroy() {
if (this.interceptors != null) {
Iterator iter = this.interceptors.iterator();
while (iter.hasNext()) {
((ExceptionInterceptor) iter.next()).destroy();
}
}
}
public void init(Connection conn, Properties properties) throws SQLException {
if (this.interceptors != null) {
Iterator iter = this.interceptors.iterator();
while (iter.hasNext()) {
((ExceptionInterceptor) iter.next()).init(conn, properties);
}
}
}
}
/**
* 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 {
String componentOne;
String componentTwo;
int hashCode;
CompoundCacheKey(String partOne, String partTwo) {
this.componentOne = partOne;
this.componentTwo = partTwo;
// Handle first component (in most cases, currentCatalog being NULL....
this.hashCode = (((this.componentOne != null) ? this.componentOne : "") + this.componentTwo).hashCode();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof CompoundCacheKey) {
CompoundCacheKey another = (CompoundCacheKey) obj;
boolean firstPartEqual = false;
if (this.componentOne == null) {
firstPartEqual = (another.componentOne == null);
} else {
firstPartEqual = this.componentOne.equals(another.componentOne);
}
return (firstPartEqual && this.componentTwo.equals(another.componentTwo));
}
return false;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return this.hashCode;
}
}
/**
* Marker for character set converter not being available (not written,
* multibyte, etc) Used to prevent multiple instantiation requests.
*/
private static final Object CHARSET_CONVERTER_NOT_AVAILABLE_MARKER = new Object();
/**
* 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 = "com.mysql.jdbc.log.StandardLogger";
private final static int HISTOGRAM_BUCKETS = 20;
/** Logger instance name */
private static final String LOGGER_INSTANCE_NAME = "MySQL";
/**
* Map mysql transaction isolation level name to
* java.sql.Connection.TRANSACTION_XXX
*/
private static Map mapTransIsolationNameToValue = null;
/** Null logger shared by all connections at startup */
private static final Log NULL_LOGGER = new NullLogger(LOGGER_INSTANCE_NAME);
protected static Map, ?> roundRobinStatsMap;
/**
* Actual collation index to collation name map for given server URLs.
*/
private static final Map> dynamicIndexToCollationMapByUrl = new HashMap>();
/**
* Actual collation index to mysql charset name map for given server URLs.
*/
private static final Map> dynamicIndexToCharsetMapByUrl = new HashMap>();
/**
* Actual collation index to mysql charset name map of user defined charsets for given server URLs.
*/
private static final Map> customIndexToCharsetMapByUrl = new HashMap>();
/**
* Actual mysql charset name to mblen map of user defined charsets for given server URLs.
*/
private static final Map> customCharsetToMblenMapByUrl = new HashMap>();
private CacheAdapter> serverConfigCache;
private long queryTimeCount;
private double queryTimeSum;
private double queryTimeSumSquares;
private double queryTimeMean;
private transient Timer cancelTimer;
private List connectionLifecycleInterceptors;
private static final Constructor> JDBC_4_CONNECTION_CTOR;
private static final int DEFAULT_RESULT_SET_TYPE = ResultSet.TYPE_FORWARD_ONLY;
private static final int DEFAULT_RESULT_SET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY;
static {
mapTransIsolationNameToValue = new HashMap(8);
mapTransIsolationNameToValue.put("READ-UNCOMMITED", TRANSACTION_READ_UNCOMMITTED);
mapTransIsolationNameToValue.put("READ-UNCOMMITTED", TRANSACTION_READ_UNCOMMITTED);
mapTransIsolationNameToValue.put("READ-COMMITTED", TRANSACTION_READ_COMMITTED);
mapTransIsolationNameToValue.put("REPEATABLE-READ", TRANSACTION_REPEATABLE_READ);
mapTransIsolationNameToValue.put("SERIALIZABLE", TRANSACTION_SERIALIZABLE);
if (Util.isJdbc4()) {
try {
JDBC_4_CONNECTION_CTOR = Class.forName("com.mysql.jdbc.JDBC4Connection").getConstructor(
new Class[] { String.class, Integer.TYPE, Properties.class, String.class, String.class });
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
} else {
JDBC_4_CONNECTION_CTOR = null;
}
}
protected static SQLException appendMessageToException(SQLException sqlEx, String messageToAppend, ExceptionInterceptor interceptor) {
String origMessage = sqlEx.getMessage();
String sqlState = sqlEx.getSQLState();
int vendorErrorCode = sqlEx.getErrorCode();
StringBuffer messageBuf = new StringBuffer(origMessage.length() + messageToAppend.length());
messageBuf.append(origMessage);
messageBuf.append(messageToAppend);
SQLException sqlExceptionWithNewMessage = SQLError.createSQLException(messageBuf.toString(), sqlState, vendorErrorCode, interceptor);
//
// Try and maintain the original stack trace, only works on JDK-1.4 and newer
//
try {
// Have to do this with reflection, otherwise older JVMs croak
Method getStackTraceMethod = null;
Method setStackTraceMethod = null;
Object theStackTraceAsObject = null;
Class> stackTraceElementClass = Class.forName("java.lang.StackTraceElement");
Class> stackTraceElementArrayClass = Array.newInstance(stackTraceElementClass, new int[] { 0 }).getClass();
getStackTraceMethod = Throwable.class.getMethod("getStackTrace", new Class[] {});
setStackTraceMethod = Throwable.class.getMethod("setStackTrace", new Class[] { stackTraceElementArrayClass });
if (getStackTraceMethod != null && setStackTraceMethod != null) {
theStackTraceAsObject = getStackTraceMethod.invoke(sqlEx, new Object[0]);
setStackTraceMethod.invoke(sqlExceptionWithNewMessage, new Object[] { theStackTraceAsObject });
}
} catch (NoClassDefFoundError noClassDefFound) {
} catch (NoSuchMethodException noSuchMethodEx) {
} catch (Throwable catchAll) {
}
return sqlExceptionWithNewMessage;
}
public Timer getCancelTimer() {
synchronized (getConnectionMutex()) {
if (this.cancelTimer == null) {
boolean createdNamedTimer = false;
// Use reflection magic to try this on JDK's 1.5 and newer, fallback to non-named timer on older VMs.
try {
Constructor ctr = Timer.class.getConstructor(new Class[] { String.class, Boolean.TYPE });
this.cancelTimer = ctr.newInstance(new Object[] { "MySQL Statement Cancellation Timer", Boolean.TRUE });
createdNamedTimer = true;
} catch (Throwable t) {
createdNamedTimer = false;
}
if (!createdNamedTimer) {
this.cancelTimer = new Timer(true);
}
}
return this.cancelTimer;
}
}
/**
* Creates a connection instance -- We need to provide factory-style methods
* so we can support both JDBC3 (and older) and JDBC4 runtimes, otherwise
* the class verifier complains when it tries to load JDBC4-only interface
* classes that are present in JDBC4 method signatures.
*/
protected static Connection getInstance(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url)
throws SQLException {
if (!Util.isJdbc4()) {
return new ConnectionImpl(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url);
}
return (Connection) Util.handleNewInstance(JDBC_4_CONNECTION_CTOR, new Object[] { hostToConnectTo, Integer.valueOf(portToConnectTo), info,
databaseToConnectTo, url }, null);
}
private static final Random random = new Random();
/**
* @param url
* @param hostList
*/
protected static synchronized int getNextRoundRobinHostIndex(String url, List> hostList) {
// we really do "random" here, because you don't get even distribution when this is coupled with connection pools
int indexRange = hostList.size();
int index = random.nextInt(indexRange);
return index;
}
private static boolean nullSafeCompare(String s1, String s2) {
if (s1 == null && s2 == null) {
return true;
}
if (s1 == null && s2 != null) {
return false;
}
return s1 != null && s1.equals(s2);
}
/** Are we in autoCommit mode? */
private boolean autoCommit = true;
/** A cache of SQL to parsed prepared statement parameters. */
private CacheAdapter cachedPreparedStatementParams;
/**
* For servers > 4.1.0, what character set is the metadata returned in?
*/
private String characterSetMetadata = null;
/**
* The character set we want results and result metadata returned in (null ==
* results in any charset, metadata in UTF-8).
*/
private String characterSetResultsOnServer = null;
/**
* Holds cached mappings to charset converters to avoid static
* synchronization and at the same time save memory (each charset converter
* takes approx 65K of static data).
*/
private Map charsetConverterMap = new HashMap(CharsetMapping.getNumberOfCharsetsConfigured());
/** The point in time when this connection was created */
private long connectionCreationTimeMillis = 0;
/** ID used when profiling */
private long connectionId;
/** The database we're currently using (called Catalog in JDBC terms). */
private String database = null;
/** Internal DBMD to use for various database-version specific features */
private DatabaseMetaData dbmd = null;
private TimeZone defaultTimeZone;
/** The event sink to use for profiling */
private ProfilerEventHandler eventSink;
/** Why was this connection implicitly closed, if known? (for diagnostics) */
private Throwable forceClosedReason;
/** Does the server suuport isolation levels? */
private boolean hasIsolationLevels = false;
/** Does this version of MySQL support quoted identifiers? */
private boolean hasQuotedIdentifiers = false;
/** The hostname we're connected to */
private String host = null;
/**
* We need this 'bootstrapped', because 4.1 and newer will send fields back
* with this even before we fill this dynamically from the server.
*/
public Map indexToMysqlCharset = new HashMap();
public Map indexToCustomMysqlCharset = null; //new HashMap();
private Map mysqlCharsetToCustomMblen = null; //new HashMap();
/** The I/O abstraction interface (network conn to MySQL server */
private transient MysqlIO io = null;
private boolean isClientTzUTC = false;
/** Has this connection been closed? */
private boolean isClosed = true;
/** Is this connection associated with a global tx? */
private boolean isInGlobalTx = false;
/** Is this connection running inside a JDK-1.3 VM? */
private boolean isRunningOnJDK13 = false;
/** isolation level */
private int isolationLevel = java.sql.Connection.TRANSACTION_READ_COMMITTED;
private boolean isServerTzUTC = false;
/** When did the last query finish? */
private long lastQueryFinishedTime = 0;
/** The logger we're going to use */
private transient Log log = NULL_LOGGER;
/**
* If gathering metrics, what was the execution time of the longest query so
* far ?
*/
private long longestQueryTimeMs = 0;
/** Is the server configured to use lower-case table names only? */
private boolean lowerCaseTableNames = false;
/** When did the master fail? */
// private long masterFailTimeMillis = 0L;
private long maximumNumberTablesAccessed = 0;
/** The max-rows setting for current session */
private int sessionMaxRows = -1;
/** When was the last time we reported metrics? */
private long metricsLastReportedMs;
private long minimumNumberTablesAccessed = Long.MAX_VALUE;
/** The JDBC URL we're using */
private String myURL = null;
/** Does this connection need to be tested? */
private boolean needsPing = false;
private int netBufferLength = 16384;
private boolean noBackslashEscapes = false;
private long numberOfPreparedExecutes = 0;
private long numberOfPrepares = 0;
private long numberOfQueriesIssued = 0;
private long numberOfResultSetsCreated = 0;
private long[] numTablesMetricsHistBreakpoints;
private int[] numTablesMetricsHistCounts;
private long[] oldHistBreakpoints = null;
private int[] oldHistCounts = null;
/** A map of currently open statements */
private Map openStatements;
private LRUCache parsedCallableStatementCache;
private boolean parserKnowsUnicode = false;
/** The password we used */
private String password = null;
private long[] perfMetricsHistBreakpoints;
private int[] perfMetricsHistCounts;
/** Point of origin where this Connection was created */
private String pointOfOrigin;
/** The port number we're connected to (defaults to 3306) */
private int port = 3306;
/** Properties for this connection specified by user */
protected Properties props = null;
/** Should we retrieve 'info' messages from the server? */
private boolean readInfoMsg = false;
/** Are we in read-only mode? */
private boolean readOnly = false;
/** Cache of ResultSet metadata */
protected LRUCache resultSetMetadataCache;
/** The timezone of the server */
private TimeZone serverTimezoneTZ = null;
/** The map of server variables that we retrieve at connection init. */
private Map serverVariables = null;
private long shortestQueryTimeMs = Long.MAX_VALUE;
private double totalQueryTimeMs = 0;
/** Are transactions supported by the MySQL server we are connected to? */
private boolean transactionsSupported = false;
/**
* The type map for UDTs (not implemented, but used by some third-party
* vendors, most notably IBM WebSphere)
*/
private Map> typeMap;
/** Has ANSI_QUOTES been enabled on the server? */
private boolean useAnsiQuotes = false;
/** The user we're connected as */
private String user = null;
/**
* Should we use server-side prepared statements? (auto-detected, but can be
* disabled by user)
*/
private boolean useServerPreparedStmts = false;
private LRUCache serverSideStatementCheckCache;
private LRUCache serverSideStatementCache;
private Calendar sessionCalendar;
private Calendar utcCalendar;
private String origHostToConnectTo;
// we don't want to be able to publicly clone this...
private int origPortToConnectTo;
private String origDatabaseToConnectTo;
private String errorMessageEncoding = "Cp1252"; // to begin with, changes after we talk to the server
private boolean usePlatformCharsetConverters;
/*
* For testing failover scenarios
*/
private boolean hasTriedMasterFlag = false;
/**
* The comment (if any) that we'll prepend to all statements
* sent to the server (to show up in "SHOW PROCESSLIST")
*/
private String statementComment = null;
private boolean storesLowerCaseTableName;
private List statementInterceptors;
/**
* If a CharsetEncoder is required for escaping. Needed for SJIS and related
* problems with \u00A5.
*/
private boolean requiresEscapingEncoder;
private String hostPortPair;
/**
* '
* For the delegate only
*/
protected ConnectionImpl() {
}
/**
* Creates a connection to a MySQL Server.
*
* @param hostToConnectTo
* the hostname of the database server
* @param portToConnectTo
* the port number the server is listening on
* @param info
* a Properties[] list holding the user and password
* @param databaseToConnectTo
* the database to connect to
* @param url
* the URL of the connection
* @param d
* the Driver instantation of the connection
* @exception SQLException
* if a database access error occurs
*/
public ConnectionImpl(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url) throws SQLException {
this.connectionCreationTimeMillis = System.currentTimeMillis();
if (databaseToConnectTo == null) {
databaseToConnectTo = "";
}
// Stash away for later, used to clone this connection for Statement.cancel and Statement.setQueryTimeout().
//
this.origHostToConnectTo = hostToConnectTo;
this.origPortToConnectTo = portToConnectTo;
this.origDatabaseToConnectTo = databaseToConnectTo;
try {
Blob.class.getMethod("truncate", new Class[] { Long.TYPE });
this.isRunningOnJDK13 = false;
} catch (NoSuchMethodException nsme) {
this.isRunningOnJDK13 = true;
}
this.sessionCalendar = new GregorianCalendar();
this.utcCalendar = new GregorianCalendar();
this.utcCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));
//
// Normally, this code would be in initializeDriverProperties, but we need to do this as early as possible, so we can start logging to the 'correct'
// place as early as possible...this.log points to 'NullLogger' for every connection at startup to avoid NPEs and the overhead of checking for NULL at
// every logging call.
//
// We will reset this to the configured logger during properties initialization.
//
this.log = LogFactory.getLogger(getLogger(), LOGGER_INSTANCE_NAME, getExceptionInterceptor());
// We store this per-connection, due to static synchronization issues in Java's built-in TimeZone class...
this.defaultTimeZone = Util.getDefaultTimeZone();
this.isClientTzUTC = "GMT".equalsIgnoreCase(this.defaultTimeZone.getID());
this.openStatements = new HashMap();
if (NonRegisteringDriver.isHostPropertiesList(hostToConnectTo)) {
Properties hostSpecificProps = NonRegisteringDriver.expandHostKeyValues(hostToConnectTo);
Enumeration> propertyNames = hostSpecificProps.propertyNames();
while (propertyNames.hasMoreElements()) {
String propertyName = propertyNames.nextElement().toString();
String propertyValue = hostSpecificProps.getProperty(propertyName);
info.setProperty(propertyName, propertyValue);
}
} else {
if (hostToConnectTo == null) {
this.host = "localhost";
this.hostPortPair = this.host + ":" + portToConnectTo;
} else {
this.host = hostToConnectTo;
if (hostToConnectTo.indexOf(":") == -1) {
this.hostPortPair = this.host + ":" + portToConnectTo;
} else {
this.hostPortPair = this.host;
}
}
}
this.port = portToConnectTo;
this.database = databaseToConnectTo;
this.myURL = url;
this.user = info.getProperty(NonRegisteringDriver.USER_PROPERTY_KEY);
this.password = info.getProperty(NonRegisteringDriver.PASSWORD_PROPERTY_KEY);
if ((this.user == null) || this.user.equals("")) {
this.user = "";
}
if (this.password == null) {
this.password = "";
}
this.props = info;
initializeDriverProperties(info);
if (getUseUsageAdvisor()) {
this.pointOfOrigin = LogUtils.findCallingClassAndMethod(new Throwable());
} else {
this.pointOfOrigin = "";
}
try {
this.dbmd = getMetaData(false, false);
initializeSafeStatementInterceptors();
createNewIO(false);
unSafeStatementInterceptors();
} catch (SQLException ex) {
cleanup(ex);
// don't clobber SQL exceptions
throw ex;
} catch (Exception ex) {
cleanup(ex);
StringBuffer mesg = new StringBuffer(128);
if (!getParanoid()) {
mesg.append("Cannot connect to MySQL server on ");
mesg.append(this.host);
mesg.append(":");
mesg.append(this.port);
mesg.append(".\n\n");
mesg.append("Make sure that there is a MySQL server ");
mesg.append("running on the machine/port you are trying ");
mesg.append("to connect to and that the machine this software is running on ");
mesg.append("is able to connect to this host/port (i.e. not firewalled). ");
mesg.append("Also make sure that the server has not been started with the --skip-networking ");
mesg.append("flag.\n\n");
} else {
mesg.append("Unable to connect to database.");
}
SQLException sqlEx = SQLError.createSQLException(mesg.toString(), SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, getExceptionInterceptor());
sqlEx.initCause(ex);
throw sqlEx;
}
NonRegisteringDriver.trackConnection(this);
}
public void unSafeStatementInterceptors() throws SQLException {
ArrayList unSafedStatementInterceptors = new ArrayList(this.statementInterceptors.size());
for (int i = 0; i < this.statementInterceptors.size(); i++) {
NoSubInterceptorWrapper wrappedInterceptor = (NoSubInterceptorWrapper) this.statementInterceptors.get(i);
unSafedStatementInterceptors.add(wrappedInterceptor.getUnderlyingInterceptor());
}
this.statementInterceptors = unSafedStatementInterceptors;
if (this.io != null) {
this.io.setStatementInterceptors(this.statementInterceptors);
}
}
public void initializeSafeStatementInterceptors() throws SQLException {
this.isClosed = false;
List unwrappedInterceptors = Util.loadExtensions(this, this.props, getStatementInterceptors(), "MysqlIo.BadStatementInterceptor",
getExceptionInterceptor());
this.statementInterceptors = new ArrayList(unwrappedInterceptors.size());
for (int i = 0; i < unwrappedInterceptors.size(); i++) {
Extension interceptor = unwrappedInterceptors.get(i);
// adapt older versions of statement interceptors, handle the case where something wants v2 functionality but wants to run with an older driver
if (interceptor instanceof StatementInterceptor) {
if (ReflectiveStatementInterceptorAdapter.getV2PostProcessMethod(interceptor.getClass()) != null) {
this.statementInterceptors.add(new NoSubInterceptorWrapper(new ReflectiveStatementInterceptorAdapter((StatementInterceptor) interceptor)));
} else {
this.statementInterceptors.add(new NoSubInterceptorWrapper(new V1toV2StatementInterceptorAdapter((StatementInterceptor) interceptor)));
}
} else {
this.statementInterceptors.add(new NoSubInterceptorWrapper((StatementInterceptorV2) interceptor));
}
}
}
public List getStatementInterceptorsInstances() {
return this.statementInterceptors;
}
private void addToHistogram(int[] histogramCounts, long[] histogramBreakpoints, long value, int numberOfTimes, long currentLowerBound,
long currentUpperBound) {
if (histogramCounts == null) {
createInitialHistogram(histogramBreakpoints, currentLowerBound, currentUpperBound);
} else {
for (int i = 0; i < HISTOGRAM_BUCKETS; i++) {
if (histogramBreakpoints[i] >= value) {
histogramCounts[i] += numberOfTimes;
break;
}
}
}
}
private void addToPerformanceHistogram(long value, int numberOfTimes) {
checkAndCreatePerformanceHistogram();
addToHistogram(this.perfMetricsHistCounts, this.perfMetricsHistBreakpoints, value, numberOfTimes, this.shortestQueryTimeMs == Long.MAX_VALUE ? 0
: this.shortestQueryTimeMs, this.longestQueryTimeMs);
}
private void addToTablesAccessedHistogram(long value, int numberOfTimes) {
checkAndCreateTablesAccessedHistogram();
addToHistogram(this.numTablesMetricsHistCounts, this.numTablesMetricsHistBreakpoints, value, numberOfTimes,
this.minimumNumberTablesAccessed == Long.MAX_VALUE ? 0 : this.minimumNumberTablesAccessed, this.maximumNumberTablesAccessed);
}
/**
* Builds the map needed for 4.1.0 and newer servers that maps field-level
* charset/collation info to a java character encoding name.
*
* @throws SQLException
*/
private void buildCollationMapping() throws SQLException {
Map indexToCharset = null;
Map sortedCollationMap = null;
Map customCharset = null;
Map customMblen = null;
if (getCacheServerConfiguration()) {
synchronized (dynamicIndexToCharsetMapByUrl) {
indexToCharset = dynamicIndexToCharsetMapByUrl.get(getURL());
sortedCollationMap = dynamicIndexToCollationMapByUrl.get(getURL());
customCharset = customIndexToCharsetMapByUrl.get(getURL());
customMblen = customCharsetToMblenMapByUrl.get(getURL());
}
}
if (indexToCharset == null) {
indexToCharset = new HashMap();
if (versionMeetsMinimum(4, 1, 0) && getDetectCustomCollations()) {
java.sql.Statement stmt = null;
java.sql.ResultSet results = null;
try {
sortedCollationMap = new TreeMap();
customCharset = new HashMap();
customMblen = new HashMap();
stmt = getMetadataSafeStatement();
try {
results = stmt.executeQuery("SHOW COLLATION");
if (versionMeetsMinimum(5, 0, 0)) {
Util.resultSetToMap(sortedCollationMap, results, 3, 2);
} else {
while (results.next()) {
sortedCollationMap.put(results.getLong(3), results.getString(2));
}
}
} catch (SQLException ex) {
if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
throw ex;
}
}
for (Iterator> indexIter = sortedCollationMap.entrySet().iterator(); indexIter.hasNext();) {
Map.Entry indexEntry = indexIter.next();
int collationIndex = indexEntry.getKey().intValue();
String charsetName = indexEntry.getValue();
indexToCharset.put(collationIndex, charsetName);
// if no static map for charsetIndex or server has a different mapping then our static map, adding it to custom map
if (collationIndex >= CharsetMapping.MAP_SIZE
|| !charsetName.equals(CharsetMapping.getMysqlCharsetNameForCollationIndex(collationIndex))) {
customCharset.put(collationIndex, charsetName);
}
// if no static map for charsetName adding to custom map
if (!CharsetMapping.CHARSET_NAME_TO_CHARSET.containsKey(charsetName)) {
customMblen.put(charsetName, null);
}
}
// if there is a number of custom charsets we should execute SHOW CHARACTER SET to know theirs mblen
if (customMblen.size() > 0) {
try {
results = stmt.executeQuery("SHOW CHARACTER SET");
while (results.next()) {
String charsetName = results.getString("Charset");
if (customMblen.containsKey(charsetName)) {
customMblen.put(charsetName, results.getInt("Maxlen"));
}
}
} catch (SQLException ex) {
if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
throw ex;
}
}
}
if (getCacheServerConfiguration()) {
synchronized (dynamicIndexToCharsetMapByUrl) {
dynamicIndexToCharsetMapByUrl.put(getURL(), indexToCharset);
dynamicIndexToCollationMapByUrl.put(getURL(), sortedCollationMap);
customIndexToCharsetMapByUrl.put(getURL(), customCharset);
customCharsetToMblenMapByUrl.put(getURL(), customMblen);
}
}
} catch (SQLException ex) {
throw ex;
} catch (RuntimeException ex) {
SQLException sqlEx = SQLError.createSQLException(ex.toString(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, null);
sqlEx.initCause(ex);
throw sqlEx;
} finally {
if (results != null) {
try {
results.close();
} catch (java.sql.SQLException sqlE) {
// ignore
}
}
if (stmt != null) {
try {
stmt.close();
} catch (java.sql.SQLException sqlE) {
// ignore
}
}
}
} else {
for (int i = 1; i < CharsetMapping.MAP_SIZE; i++) {
indexToCharset.put(i, CharsetMapping.getMysqlCharsetNameForCollationIndex(i));
}
if (getCacheServerConfiguration()) {
synchronized (dynamicIndexToCharsetMapByUrl) {
dynamicIndexToCharsetMapByUrl.put(getURL(), indexToCharset);
}
}
}
}
this.indexToMysqlCharset = Collections.unmodifiableMap(indexToCharset);
if (customCharset != null) {
this.indexToCustomMysqlCharset = Collections.unmodifiableMap(customCharset);
}
if (customMblen != null) {
this.mysqlCharsetToCustomMblen = Collections.unmodifiableMap(customMblen);
}
}
private boolean canHandleAsServerPreparedStatement(String sql) throws SQLException {
if (sql == null || sql.length() == 0) {
return true;
}
if (!this.useServerPreparedStmts) {
return false;
}
if (getCachePreparedStatements()) {
synchronized (this.serverSideStatementCheckCache) {
Boolean flag = (Boolean) this.serverSideStatementCheckCache.get(sql);
if (flag != null) {
return flag.booleanValue();
}
boolean canHandle = canHandleAsServerPreparedStatementNoCache(sql);
if (sql.length() < getPreparedStatementCacheSqlLimit()) {
this.serverSideStatementCheckCache.put(sql, canHandle ? Boolean.TRUE : Boolean.FALSE);
}
return canHandle;
}
}
return canHandleAsServerPreparedStatementNoCache(sql);
}
private boolean canHandleAsServerPreparedStatementNoCache(String sql) throws SQLException {
// Can't use server-side prepare for CALL
if (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, "CALL")) {
return false;
}
boolean canHandleAsStatement = true;
if (!versionMeetsMinimum(5, 0, 7)
&& (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, "SELECT") || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, "DELETE")
|| StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, "INSERT")
|| StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, "UPDATE") || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,
"REPLACE"))) {
// check for limit ?[,?]
/*
* The grammar for this (from the server) is: ULONG_NUM | ULONG_NUM ',' ULONG_NUM | ULONG_NUM OFFSET_SYM ULONG_NUM
*/
int currentPos = 0;
int statementLength = sql.length();
int lastPosToLook = statementLength - 7; // "LIMIT ".length()
boolean allowBackslashEscapes = !this.noBackslashEscapes;
String quoteChar = this.useAnsiQuotes ? "\"" : "'";
boolean foundLimitWithPlaceholder = false;
while (currentPos < lastPosToLook) {
int limitStart = StringUtils.indexOfIgnoreCase(currentPos, sql, "LIMIT ", quoteChar, quoteChar,
allowBackslashEscapes ? StringUtils.SEARCH_MODE__ALL : StringUtils.SEARCH_MODE__MRK_COM_WS);
if (limitStart == -1) {
break;
}
currentPos = limitStart + 7;
while (currentPos < statementLength) {
char c = sql.charAt(currentPos);
//
// Have we reached the end of what can be in a LIMIT clause?
//
if (!Character.isDigit(c) && !Character.isWhitespace(c) && c != ',' && c != '?') {
break;
}
if (c == '?') {
foundLimitWithPlaceholder = true;
break;
}
currentPos++;
}
}
canHandleAsStatement = !foundLimitWithPlaceholder;
} else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "XA ")) {
canHandleAsStatement = false;
} else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "CREATE TABLE")) {
canHandleAsStatement = false;
} else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "DO")) {
canHandleAsStatement = false;
} else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "SET")) {
canHandleAsStatement = false;
}
return canHandleAsStatement;
}
/**
* Changes the user on this connection by performing a re-authentication. If
* authentication fails, the connection will remain under the context of the
* current user.
*
* @param userName
* the username to authenticate with
* @param newPassword
* the password to authenticate with
* @throws SQLException
* if authentication fails, or some other error occurs while
* performing the command.
*/
public void changeUser(String userName, String newPassword) throws SQLException {
synchronized (getConnectionMutex()) {
checkClosed();
if ((userName == null) || userName.equals("")) {
userName = "";
}
if (newPassword == null) {
newPassword = "";
}
// reset maxRows to default value
this.sessionMaxRows = -1;
try {
this.io.changeUser(userName, newPassword, this.database);
} catch (SQLException ex) {
if (versionMeetsMinimum(5, 6, 13) && "28000".equals(ex.getSQLState())) {
cleanup(ex);
}
throw ex;
}
this.user = userName;
this.password = newPassword;
if (versionMeetsMinimum(4, 1, 0)) {
configureClientCharacterSet(true);
}
setSessionVariables();
setupServerForTruncationChecks();
}
}
private boolean characterSetNamesMatches(String mysqlEncodingName) {
// set names is equivalent to character_set_client ..._results and ..._connection, but we set _results later, so don't check it here.
return (mysqlEncodingName != null && mysqlEncodingName.equalsIgnoreCase(this.serverVariables.get("character_set_client")) && mysqlEncodingName
.equalsIgnoreCase(this.serverVariables.get("character_set_connection")));
}
private void checkAndCreatePerformanceHistogram() {
if (this.perfMetricsHistCounts == null) {
this.perfMetricsHistCounts = new int[HISTOGRAM_BUCKETS];
}
if (this.perfMetricsHistBreakpoints == null) {
this.perfMetricsHistBreakpoints = new long[HISTOGRAM_BUCKETS];
}
}
private void checkAndCreateTablesAccessedHistogram() {
if (this.numTablesMetricsHistCounts == null) {
this.numTablesMetricsHistCounts = new int[HISTOGRAM_BUCKETS];
}
if (this.numTablesMetricsHistBreakpoints == null) {
this.numTablesMetricsHistBreakpoints = new long[HISTOGRAM_BUCKETS];
}
}
public void checkClosed() throws SQLException {
if (this.isClosed) {
throwConnectionClosedException();
}
}
public void throwConnectionClosedException() throws SQLException {
StringBuffer messageBuf = new StringBuffer("No operations allowed after connection closed.");
SQLException ex = SQLError.createSQLException(messageBuf.toString(), SQLError.SQL_STATE_CONNECTION_NOT_OPEN, getExceptionInterceptor());
if (this.forceClosedReason != null) {
ex.initCause(this.forceClosedReason);
}
throw ex;
}
/**
* If useUnicode flag is set and explicit client character encoding isn't
* specified then assign encoding from server if any.
*
* @throws SQLException
*/
private void checkServerEncoding() throws SQLException {
if (getUseUnicode() && (getEncoding() != null)) {
// spec'd by client, don't map
return;
}
String serverCharset = this.serverVariables.get("character_set");
if (serverCharset == null) {
// must be 4.1.1 or newer?
serverCharset = this.serverVariables.get("character_set_server");
}
String mappedServerEncoding = null;
if (serverCharset != null) {
try {
mappedServerEncoding = CharsetMapping.getJavaEncodingForMysqlCharset(serverCharset);
} catch (RuntimeException ex) {
SQLException sqlEx = SQLError.createSQLException(ex.toString(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, null);
sqlEx.initCause(ex);
throw sqlEx;
}
}
//
// First check if we can do the encoding ourselves
//
if (!getUseUnicode() && (mappedServerEncoding != null)) {
SingleByteCharsetConverter converter = getCharsetConverter(mappedServerEncoding);
if (converter != null) { // we know how to convert this ourselves
setUseUnicode(true); // force the issue
setEncoding(mappedServerEncoding);
return;
}
}
//
// Now, try and find a Java I/O converter that can do the encoding for us
//
if (serverCharset != null) {
if (mappedServerEncoding == null) {
// We don't have a mapping for it, so try and canonicalize the name....
if (Character.isLowerCase(serverCharset.charAt(0))) {
char[] ach = serverCharset.toCharArray();
ach[0] = Character.toUpperCase(serverCharset.charAt(0));
setEncoding(new String(ach));
}
}
if (mappedServerEncoding == null) {
throw SQLError.createSQLException("Unknown character encoding on server '" + serverCharset + "', use 'characterEncoding=' property "
+ " to provide correct mapping", SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, getExceptionInterceptor());
}
//
// Attempt to use the encoding, and bail out if it can't be used
//
try {
StringUtils.getBytes("abc", mappedServerEncoding);
setEncoding(mappedServerEncoding);
setUseUnicode(true);
} catch (UnsupportedEncodingException UE) {
throw SQLError.createSQLException("The driver can not map the character encoding '" + getEncoding() + "' that your server is using "
+ "to a character encoding your JVM understands. You can specify this mapping manually by adding \"useUnicode=true\" "
+ "as well as \"characterEncoding=[an_encoding_your_jvm_understands]\" to your JDBC URL.", "0S100", getExceptionInterceptor());
}
}
}
/**
* Set transaction isolation level to the value received from server if any.
* Is called by connectionInit(...)
*
* @throws SQLException
*/
private void checkTransactionIsolationLevel() throws SQLException {
String txIsolationName = null;
if (versionMeetsMinimum(4, 0, 3)) {
txIsolationName = "tx_isolation";
} else {
txIsolationName = "transaction_isolation";
}
String s = this.serverVariables.get(txIsolationName);
if (s != null) {
Integer intTI = mapTransIsolationNameToValue.get(s);
if (intTI != null) {
this.isolationLevel = intTI.intValue();
}
}
}
/**
* Clobbers the physical network connection and marks
* this connection as closed.
*
* @throws SQLException
*/
public void abortInternal() throws SQLException {
if (this.io != null) {
try {
this.io.forceClose();
} catch (Throwable t) {
// can't do anything about it, and we're forcibly aborting
}
this.io.releaseResources();
this.io = null;
}
this.isClosed = true;
}
/**
* Destroys this connection and any underlying resources
*
* @param fromWhere
* @param whyCleanedUp
*/
private void cleanup(Throwable whyCleanedUp) {
try {
if (this.io != null) {
if (isClosed()) {
this.io.forceClose();
} else {
realClose(false, false, false, whyCleanedUp);
}
}
} catch (SQLException sqlEx) {
// ignore, we're going away.
}
this.isClosed = true;
}
public void clearHasTriedMaster() {
this.hasTriedMasterFlag = false;
}
/**
* After this call, getWarnings returns null until a new warning is reported
* for this connection.
*
* @exception SQLException
* if a database access error occurs
*/
public void clearWarnings() throws SQLException {
// firstWarning = null;
}
/**
* @param sql
* @throws SQLException
*/
public java.sql.PreparedStatement clientPrepareStatement(String sql) throws SQLException {
return clientPrepareStatement(sql, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY);
}
/**
* @see Connection#prepareStatement(String, int)
*/
public java.sql.PreparedStatement clientPrepareStatement(String sql, int autoGenKeyIndex) throws SQLException {
java.sql.PreparedStatement pStmt = clientPrepareStatement(sql);
((com.mysql.jdbc.PreparedStatement) pStmt).setRetrieveGeneratedKeys(autoGenKeyIndex == java.sql.Statement.RETURN_GENERATED_KEYS);
return pStmt;
}
/**
* @param sql
* @param resultSetType
* @param resultSetConcurrency
* @throws SQLException
*/
public java.sql.PreparedStatement clientPrepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return clientPrepareStatement(sql, resultSetType, resultSetConcurrency, true);
}
public java.sql.PreparedStatement clientPrepareStatement(String sql, int resultSetType, int resultSetConcurrency, boolean processEscapeCodesIfNeeded)
throws SQLException {
checkClosed();
String nativeSql = processEscapeCodesIfNeeded && getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql) : sql;
PreparedStatement pStmt = null;
if (getCachePreparedStatements()) {
PreparedStatement.ParseInfo pStmtInfo = this.cachedPreparedStatementParams.get(nativeSql);
if (pStmtInfo == null) {
pStmt = com.mysql.jdbc.PreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql, this.database);
this.cachedPreparedStatementParams.put(nativeSql, pStmt.getParseInfo());
} else {
pStmt = new com.mysql.jdbc.PreparedStatement(getLoadBalanceSafeProxy(), nativeSql, this.database, pStmtInfo);
}
} else {
pStmt = com.mysql.jdbc.PreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql, this.database);
}
pStmt.setResultSetType(resultSetType);
pStmt.setResultSetConcurrency(resultSetConcurrency);
return pStmt;
}
/**
* @see java.sql.Connection#prepareStatement(String, int[])
*/
public java.sql.PreparedStatement clientPrepareStatement(String sql, int[] autoGenKeyIndexes) throws SQLException {
PreparedStatement pStmt = (PreparedStatement) clientPrepareStatement(sql);
pStmt.setRetrieveGeneratedKeys((autoGenKeyIndexes != null) && (autoGenKeyIndexes.length > 0));
return pStmt;
}
/**
* @see java.sql.Connection#prepareStatement(String, String[])
*/
public java.sql.PreparedStatement clientPrepareStatement(String sql, String[] autoGenKeyColNames) throws SQLException {
PreparedStatement pStmt = (PreparedStatement) clientPrepareStatement(sql);
pStmt.setRetrieveGeneratedKeys((autoGenKeyColNames != null) && (autoGenKeyColNames.length > 0));
return pStmt;
}
public java.sql.PreparedStatement clientPrepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
return clientPrepareStatement(sql, resultSetType, resultSetConcurrency, true);
}
// --------------------------JDBC 2.0-----------------------------
/**
* In some cases, it is desirable to immediately release a Connection's
* database and JDBC resources instead of waiting for them to be
* automatically released (cant think why off the top of my head) Note:
* A Connection is automatically closed when it is garbage collected.
* Certain fatal errors also result in a closed connection.
*
* @exception SQLException
* if a database access error occurs
*/
public void close() throws SQLException {
synchronized (getConnectionMutex()) {
if (this.connectionLifecycleInterceptors != null) {
new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
@Override
void forEach(Extension each) throws SQLException {
((ConnectionLifecycleInterceptor) each).close();
}
}.doForAll();
}
realClose(true, true, false, null);
}
}
/**
* Closes all currently open statements.
*
* @throws SQLException
*/
private void closeAllOpenStatements() throws SQLException {
SQLException postponedException = null;
if (this.openStatements != null) {
List currentlyOpenStatements = new ArrayList(); // we need this to
// avoid ConcurrentModificationEx
for (Iterator iter = this.openStatements.keySet().iterator(); iter.hasNext();) {
currentlyOpenStatements.add(iter.next());
}
int numStmts = currentlyOpenStatements.size();
for (int i = 0; i < numStmts; i++) {
StatementImpl stmt = (StatementImpl) currentlyOpenStatements.get(i);
try {
stmt.realClose(false, true);
} catch (SQLException sqlEx) {
postponedException = sqlEx; // throw it later, cleanup all
// statements first
}
}
if (postponedException != null) {
throw postponedException;
}
}
}
private void closeStatement(java.sql.Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) {
// ignore
}
stmt = null;
}
}
/**
* The method commit() makes all changes made since the previous
* commit/rollback permanent and releases any database locks currently held
* by the Connection. This method should only be used when auto-commit has
* been disabled.
*
* 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 iter = new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
@Override
void forEach(Extension each) throws SQLException {
if (!((ConnectionLifecycleInterceptor) each).commit()) {
this.stopIterating = true;
}
}
};
iter.doForAll();
if (!iter.fullIteration()) {
return;
}
}
// no-op if _relaxAutoCommit == true
if (this.autoCommit && !getRelaxAutoCommit()) {
throw SQLError.createSQLException("Can't call commit when autocommit=true", getExceptionInterceptor());
} else if (this.transactionsSupported) {
if (getUseLocalTransactionState() && versionMeetsMinimum(5, 0, 0)) {
if (!this.io.inTransactionOnServer()) {
return; // effectively a no-op
}
}
execSQL(null, "commit", -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false, this.database, null, false);
}
} catch (SQLException sqlException) {
if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE.equals(sqlException.getSQLState())) {
throw SQLError.createSQLException("Communications link failure during commit(). Transaction resolution unknown.",
SQLError.SQL_STATE_TRANSACTION_RESOLUTION_UNKNOWN, getExceptionInterceptor());
}
throw sqlException;
} finally {
this.needsPing = this.getReconnectAtTxEnd();
}
}
return;
}
/**
* Configures client-side properties for character set information.
*
* @throws SQLException
* if unable to configure the specified character set.
*/
private void configureCharsetProperties() throws SQLException {
if (getEncoding() != null) {
// Attempt to use the encoding, and bail out if it can't be used
try {
String testString = "abc";
StringUtils.getBytes(testString, getEncoding());
} catch (UnsupportedEncodingException UE) {
// Try the MySQL character encoding, then....
String oldEncoding = getEncoding();
try {
setEncoding(CharsetMapping.getJavaEncodingForMysqlCharset(oldEncoding));
} catch (RuntimeException ex) {
SQLException sqlEx = SQLError.createSQLException(ex.toString(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, null);
sqlEx.initCause(ex);
throw sqlEx;
}
if (getEncoding() == null) {
throw SQLError.createSQLException("Java does not support the MySQL character encoding '" + oldEncoding + "'.",
SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, getExceptionInterceptor());
}
try {
String testString = "abc";
StringUtils.getBytes(testString, getEncoding());
} catch (UnsupportedEncodingException encodingEx) {
throw SQLError.createSQLException("Unsupported character encoding '" + getEncoding() + "'.",
SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, getExceptionInterceptor());
}
}
}
}
/**
* Sets up client character set for MySQL-4.1 and newer if the user This
* must be done before any further communication with the server!
*
* @return true if this routine actually configured the client character
* set, or false if the driver needs to use 'older' methods to
* detect the character set, as it is connected to a MySQL server
* older than 4.1.0
* @throws SQLException
* if an exception happens while sending 'SET NAMES' to the
* server, or the server sends character set information that
* the client doesn't know about.
*/
private boolean configureClientCharacterSet(boolean dontCheckServerMatch) throws SQLException {
String realJavaEncoding = getEncoding();
boolean characterSetAlreadyConfigured = false;
try {
if (versionMeetsMinimum(4, 1, 0)) {
characterSetAlreadyConfigured = true;
setUseUnicode(true);
configureCharsetProperties();
realJavaEncoding = getEncoding(); // we need to do this again to grab this for versions > 4.1.0
try {
// Fault injection for testing server character set indices
if (this.props != null && this.props.getProperty("com.mysql.jdbc.faultInjection.serverCharsetIndex") != null) {
this.io.serverCharsetIndex = Integer.parseInt(this.props.getProperty("com.mysql.jdbc.faultInjection.serverCharsetIndex"));
}
String serverEncodingToSet = CharsetMapping.getJavaEncodingForCollationIndex(this.io.serverCharsetIndex);
if (serverEncodingToSet == null || serverEncodingToSet.length() == 0) {
if (realJavaEncoding != null) {
// user knows best, try it
setEncoding(realJavaEncoding);
} else {
throw SQLError.createSQLException("Unknown initial character set index '" + this.io.serverCharsetIndex
+ "' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
}
// "latin1" on MySQL-4.1.0+ is actually CP1252, not ISO8859_1
if (versionMeetsMinimum(4, 1, 0) && "ISO8859_1".equalsIgnoreCase(serverEncodingToSet)) {
serverEncodingToSet = "Cp1252";
}
if ("UnicodeBig".equalsIgnoreCase(serverEncodingToSet) || "UTF-16".equalsIgnoreCase(serverEncodingToSet)
|| "UTF-16LE".equalsIgnoreCase(serverEncodingToSet) || "UTF-32".equalsIgnoreCase(serverEncodingToSet)) {
serverEncodingToSet = "UTF-8";
}
setEncoding(serverEncodingToSet);
} catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
if (realJavaEncoding != null) {
// user knows best, try it
setEncoding(realJavaEncoding);
} else {
throw SQLError.createSQLException("Unknown initial character set index '" + this.io.serverCharsetIndex
+ "' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
} catch (SQLException ex) {
throw ex;
} catch (RuntimeException ex) {
SQLException sqlEx = SQLError.createSQLException(ex.toString(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, null);
sqlEx.initCause(ex);
throw sqlEx;
}
if (getEncoding() == null) {
// punt?
setEncoding("ISO8859_1");
}
//
// Has the user has 'forced' the character encoding via driver properties?
//
if (getUseUnicode()) {
if (realJavaEncoding != null) {
//
// Now, inform the server what character set we will be using from now-on...
//
if (realJavaEncoding.equalsIgnoreCase("UTF-8") || realJavaEncoding.equalsIgnoreCase("UTF8")) {
// charset names are case-sensitive
boolean utf8mb4Supported = versionMeetsMinimum(5, 5, 2);
boolean useutf8mb4 = utf8mb4Supported && (CharsetMapping.UTF8MB4_INDEXES.contains(this.io.serverCharsetIndex));
if (!getUseOldUTF8Behavior()) {
if (dontCheckServerMatch || !characterSetNamesMatches("utf8") || (utf8mb4Supported && !characterSetNamesMatches("utf8mb4"))) {
execSQL(null, "SET NAMES " + (useutf8mb4 ? "utf8mb4" : "utf8"), -1, null, DEFAULT_RESULT_SET_TYPE,
DEFAULT_RESULT_SET_CONCURRENCY, false, this.database, null, false);
}
} else {
execSQL(null, "SET NAMES latin1", -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false, this.database,
null, false);
}
setEncoding(realJavaEncoding);
} /* not utf-8 */else {
String mysqlCharsetName = CharsetMapping.getMysqlCharsetForJavaEncoding(realJavaEncoding.toUpperCase(Locale.ENGLISH), this);
/*
* if ("koi8_ru".equals(mysqlEncodingName)) { //
* This has a _different_ name in 4.1...
* mysqlEncodingName = "ko18r"; } else if
* ("euc_kr".equals(mysqlEncodingName)) { //
* Different name in 4.1 mysqlEncodingName =
* "euckr"; }
*/
if (mysqlCharsetName != null) {
if (dontCheckServerMatch || !characterSetNamesMatches(mysqlCharsetName)) {
execSQL(null, "SET NAMES " + mysqlCharsetName, -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false,
this.database, null, false);
}
}
// Switch driver's encoding now, since the server knows what we're sending...
//
setEncoding(realJavaEncoding);
}
} else if (getEncoding() != null) {
// Tell the server we'll use the server default charset to send our queries from now on....
String mysqlCharsetName = getServerCharset();
if (getUseOldUTF8Behavior()) {
mysqlCharsetName = "latin1";
}
boolean ucs2 = false;
if ("ucs2".equalsIgnoreCase(mysqlCharsetName) || "utf16".equalsIgnoreCase(mysqlCharsetName)
|| "utf16le".equalsIgnoreCase(mysqlCharsetName) || "utf32".equalsIgnoreCase(mysqlCharsetName)) {
mysqlCharsetName = "utf8";
ucs2 = true;
if (getCharacterSetResults() == null) {
setCharacterSetResults("UTF-8");
}
}
if (dontCheckServerMatch || !characterSetNamesMatches(mysqlCharsetName) || ucs2) {
try {
execSQL(null, "SET NAMES " + mysqlCharsetName, -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false,
this.database, null, false);
} catch (SQLException ex) {
if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
throw ex;
}
}
}
realJavaEncoding = getEncoding();
}
}
//
// We know how to deal with any charset coming back from the database, so tell the server not to do conversion if the user hasn't 'forced' a
// result-set character set
//
String onServer = null;
boolean isNullOnServer = false;
if (this.serverVariables != null) {
onServer = this.serverVariables.get("character_set_results");
isNullOnServer = onServer == null || "NULL".equalsIgnoreCase(onServer) || onServer.length() == 0;
}
if (getCharacterSetResults() == null) {
//
// Only send if needed, if we're caching server variables we -have- to send, because we don't know what it was before we cached them.
//
if (!isNullOnServer) {
try {
execSQL(null, "SET character_set_results = NULL", -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false,
this.database, null, false);
} catch (SQLException ex) {
if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
throw ex;
}
}
this.serverVariables.put(JDBC_LOCAL_CHARACTER_SET_RESULTS, null);
} else {
this.serverVariables.put(JDBC_LOCAL_CHARACTER_SET_RESULTS, onServer);
}
} else {
if (getUseOldUTF8Behavior()) {
try {
execSQL(null, "SET NAMES latin1", -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false, this.database, null,
false);
} catch (SQLException ex) {
if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
throw ex;
}
}
}
String charsetResults = getCharacterSetResults();
String mysqlEncodingName = null;
if ("UTF-8".equalsIgnoreCase(charsetResults) || "UTF8".equalsIgnoreCase(charsetResults)) {
mysqlEncodingName = "utf8";
} else if ("null".equalsIgnoreCase(charsetResults)) {
mysqlEncodingName = "NULL";
} else {
mysqlEncodingName = CharsetMapping.getMysqlCharsetForJavaEncoding(charsetResults.toUpperCase(Locale.ENGLISH), this);
}
//
// Only change the value if needed
//
if (mysqlEncodingName == null) {
throw SQLError.createSQLException("Can't map " + charsetResults + " given for characterSetResults to a supported MySQL encoding.",
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
if (!mysqlEncodingName.equalsIgnoreCase(this.serverVariables.get("character_set_results"))) {
StringBuffer setBuf = new StringBuffer("SET character_set_results = ".length() + mysqlEncodingName.length());
setBuf.append("SET character_set_results = ").append(mysqlEncodingName);
try {
execSQL(null, setBuf.toString(), -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false, this.database, null,
false);
} catch (SQLException ex) {
if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
throw ex;
}
}
this.serverVariables.put(JDBC_LOCAL_CHARACTER_SET_RESULTS, mysqlEncodingName);
// We have to set errorMessageEncoding according to new value of charsetResults for server version 5.5 and higher
if (versionMeetsMinimum(5, 5, 0)) {
this.errorMessageEncoding = charsetResults;
}
} else {
this.serverVariables.put(JDBC_LOCAL_CHARACTER_SET_RESULTS, onServer);
}
}
if (getConnectionCollation() != null) {
StringBuffer setBuf = new StringBuffer("SET collation_connection = ".length() + getConnectionCollation().length());
setBuf.append("SET collation_connection = ").append(getConnectionCollation());
try {
execSQL(null, setBuf.toString(), -1, null, DEFAULT_RESULT_SET_TYPE, DEFAULT_RESULT_SET_CONCURRENCY, false, this.database, null, false);
} catch (SQLException ex) {
if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
throw ex;
}
}
}
} else {
// Use what the server has specified
realJavaEncoding = getEncoding(); // so we don't get
// swapped out in the finally block....
}
} finally {
// Failsafe, make sure that the driver's notion of character encoding matches what the user has specified.
//
setEncoding(realJavaEncoding);
}
/**
* Check if we need a CharsetEncoder for escaping codepoints that are
* transformed to backslash (0x5c) in the connection encoding.
*/
try {
CharsetEncoder enc = Charset.forName(getEncoding()).newEncoder();
CharBuffer cbuf = CharBuffer.allocate(1);
ByteBuffer bbuf = ByteBuffer.allocate(1);
cbuf.put("\u00a5");
cbuf.position(0);
enc.encode(cbuf, bbuf, true);
if (bbuf.get(0) == '\\') {
this.requiresEscapingEncoder = true;
} else {
cbuf.clear();
bbuf.clear();
cbuf.put("\u20a9");
cbuf.position(0);
enc.encode(cbuf, bbuf, true);
if (bbuf.get(0) == '\\') {
this.requiresEscapingEncoder = true;
}
}
} catch (java.nio.charset.UnsupportedCharsetException ucex) {
// fallback to String API - for Java 1.4
try {
byte bbuf[] = StringUtils.getBytes("\u00a5", getEncoding());
if (bbuf[0] == '\\') {
this.requiresEscapingEncoder = true;
} else {
bbuf = StringUtils.getBytes("\u20a9", getEncoding());
if (bbuf[0] == '\\') {
this.requiresEscapingEncoder = true;
}
}
} catch (UnsupportedEncodingException ueex) {
throw SQLError
.createSQLException("Unable to use encoding: " + getEncoding(), SQLError.SQL_STATE_GENERAL_ERROR, ueex, getExceptionInterceptor());
}
}
return characterSetAlreadyConfigured;
}
/**
* Configures the client's timezone if required.
*
* @throws SQLException
* if the timezone the server is configured to use can't be
* mapped to a Java timezone.
*/
private void configureTimezone() throws SQLException {
String configuredTimeZoneOnServer = this.serverVariables.get("timezone");
if (configuredTimeZoneOnServer == null) {
configuredTimeZoneOnServer = this.serverVariables.get("time_zone");
if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
configuredTimeZoneOnServer = this.serverVariables.get("system_time_zone");
}
}
String canonicalTimezone = getServerTimezone();
if ((getUseTimezone() || !getUseLegacyDatetimeCode()) && configuredTimeZoneOnServer != null) {
// user can override this with driver properties, so don't detect if that's the case
if (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone)) {
try {
canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, getExceptionInterceptor());
} catch (IllegalArgumentException iae) {
throw SQLError.createSQLException(iae.getMessage(), SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
}
}
if (canonicalTimezone != null && canonicalTimezone.length() > 0) {
this.serverTimezoneTZ = TimeZone.getTimeZone(canonicalTimezone);
//
// The Calendar class has the behavior of mapping unknown timezones to 'GMT' instead of throwing an exception, so we must check for this...
//
if (!canonicalTimezone.equalsIgnoreCase("GMT") && this.serverTimezoneTZ.getID().equals("GMT")) {
throw SQLError.createSQLException("No timezone mapping entry for '" + canonicalTimezone + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
getExceptionInterceptor());
}
this.isServerTzUTC = "GMT".equalsIgnoreCase(this.serverTimezoneTZ.getID());
}
}
private void createInitialHistogram(long[] breakpoints, long lowerBound, long upperBound) {
double bucketSize = (((double) upperBound - (double) lowerBound) / HISTOGRAM_BUCKETS) * 1.25;
if (bucketSize < 1) {
bucketSize = 1;
}
for (int i = 0; i < HISTOGRAM_BUCKETS; i++) {
breakpoints[i] = lowerBound;
lowerBound += bucketSize;
}
}
/**
* Creates an IO channel to the server
*
* @param isForReconnect
* is this request for a re-connect
* @return a new MysqlIO instance connected to a server
* @throws SQLException
* if a database access error occurs
* @throws CommunicationsException
*/
public void createNewIO(boolean isForReconnect) throws SQLException {
synchronized (getConnectionMutex()) {
// Synchronization Not needed for *new* connections, but defintely for connections going through fail-over, since we might get the new connection up
// and running *enough* to start sending cached or still-open server-side prepared statements over to the backend before we get a chance to
// re-prepare them...
Properties mergedProps = exposeAsProperties(this.props);
if (!getHighAvailability()) {
connectOneTryOnly(isForReconnect, mergedProps);
return;
}
connectWithRetries(isForReconnect, mergedProps);
}
}
private void connectWithRetries(boolean isForReconnect, Properties mergedProps) throws SQLException {
double timeout = getInitialTimeout();
boolean connectionGood = false;
Exception connectionException = null;
for (int attemptCount = 0; (attemptCount < getMaxReconnects()) && !connectionGood; attemptCount++) {
try {
if (this.io != null) {
this.io.forceClose();
}
coreConnect(mergedProps);
pingInternal(false, 0);
boolean oldAutoCommit;
int oldIsolationLevel;
boolean oldReadOnly;
String oldCatalog;
synchronized (getConnectionMutex()) {
this.connectionId = this.io.getThreadId();
this.isClosed = false;
// save state from old connection
oldAutoCommit = getAutoCommit();
oldIsolationLevel = this.isolationLevel;
oldReadOnly = isReadOnly(false);
oldCatalog = getCatalog();
this.io.setStatementInterceptors(this.statementInterceptors);
}
// Server properties might be different from previous connection, so initialize again...
initializePropsFromServer();
if (isForReconnect) {
// Restore state from old connection
setAutoCommit(oldAutoCommit);
if (this.hasIsolationLevels) {
setTransactionIsolation(oldIsolationLevel);
}
setCatalog(oldCatalog);
setReadOnly(oldReadOnly);
}
connectionGood = true;
break;
} catch (Exception EEE) {
connectionException = EEE;
connectionGood = false;
}
if (connectionGood) {
break;
}
if (attemptCount > 0) {
try {
Thread.sleep((long) timeout * 1000);
} catch (InterruptedException IE) {
// ignore
}
}
} // end attempts for a single host
if (!connectionGood) {
// We've really failed!
SQLException chainedEx = SQLError.createSQLException(
Messages.getString("Connection.UnableToConnectWithRetries", new Object[] { Integer.valueOf(getMaxReconnects()) }),
SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE, getExceptionInterceptor());
chainedEx.initCause(connectionException);
throw chainedEx;
}
if (getParanoid() && !getHighAvailability()) {
this.password = null;
this.user = null;
}
if (isForReconnect) {
//
// Retrieve any 'lost' prepared statements if re-connecting
//
Iterator statementIter = this.openStatements.values().iterator();
//
// We build a list of these outside the map of open statements, because in the process of re-preparing, we might end up having to close a prepared
// statement, thus removing it from the map, and generating a ConcurrentModificationException
//
Stack serverPreparedStatements = null;
while (statementIter.hasNext()) {
Statement statementObj = statementIter.next();
if (statementObj instanceof ServerPreparedStatement) {
if (serverPreparedStatements == null) {
serverPreparedStatements = new Stack();
}
serverPreparedStatements.add(statementObj);
}
}
if (serverPreparedStatements != null) {
while (!serverPreparedStatements.isEmpty()) {
((ServerPreparedStatement) serverPreparedStatements.pop()).rePrepare();
}
}
}
}
private void coreConnect(Properties mergedProps) throws SQLException, IOException {
int newPort = 3306;
String newHost = "localhost";
String protocol = mergedProps.getProperty(NonRegisteringDriver.PROTOCOL_PROPERTY_KEY);
if (protocol != null) {
// "new" style URL
if ("tcp".equalsIgnoreCase(protocol)) {
newHost = normalizeHost(mergedProps.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY));
newPort = parsePortNumber(mergedProps.getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY, "3306"));
} else if ("pipe".equalsIgnoreCase(protocol)) {
setSocketFactoryClassName(NamedPipeSocketFactory.class.getName());
String path = mergedProps.getProperty(NonRegisteringDriver.PATH_PROPERTY_KEY);
if (path != null) {
mergedProps.setProperty(NamedPipeSocketFactory.NAMED_PIPE_PROP_NAME, path);
}
} else {
// normalize for all unknown protocols
newHost = normalizeHost(mergedProps.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY));
newPort = parsePortNumber(mergedProps.getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY, "3306"));
}
} else {
String[] parsedHostPortPair = NonRegisteringDriver.parseHostPortPair(this.hostPortPair);
newHost = parsedHostPortPair[NonRegisteringDriver.HOST_NAME_INDEX];
newHost = normalizeHost(newHost);
if (parsedHostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX] != null) {
newPort = parsePortNumber(parsedHostPortPair[NonRegisteringDriver.PORT_NUMBER_INDEX]);
}
}
this.port = newPort;
this.host = newHost;
// reset max-rows to default value
this.sessionMaxRows = -1;
this.io = new MysqlIO(newHost, newPort, mergedProps, getSocketFactoryClassName(), getProxy(), getSocketTimeout(),
this.largeRowSizeThreshold.getValueAsInt());
this.io.doHandshake(this.user, this.password, this.database);
if (versionMeetsMinimum(5, 5, 0)) {
// error messages are returned according to character_set_results which, at this point, is set from the response packet
this.errorMessageEncoding = this.io.getEncodingForHandshake();
}
}
private String normalizeHost(String hostname) {
if (hostname == null || StringUtils.isEmptyOrWhitespaceOnly(hostname)) {
return "localhost";
}
return hostname;
}
private int parsePortNumber(String portAsString) throws SQLException {
int portNumber = 3306;
try {
portNumber = Integer.parseInt(portAsString);
} catch (NumberFormatException nfe) {
throw SQLError.createSQLException("Illegal connection port value '" + portAsString + "'", SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE,
getExceptionInterceptor());
}
return portNumber;
}
private void connectOneTryOnly(boolean isForReconnect, Properties mergedProps) throws SQLException {
Exception connectionNotEstablishedBecause = null;
try {
coreConnect(mergedProps);
this.connectionId = this.io.getThreadId();
this.isClosed = false;
// save state from old connection
boolean oldAutoCommit = getAutoCommit();
int oldIsolationLevel = this.isolationLevel;
boolean oldReadOnly = isReadOnly(false);
String oldCatalog = getCatalog();
this.io.setStatementInterceptors(this.statementInterceptors);
// Server properties might be different from previous connection, so initialize again...
initializePropsFromServer();
if (isForReconnect) {
// Restore state from old connection
setAutoCommit(oldAutoCommit);
if (this.hasIsolationLevels) {
setTransactionIsolation(oldIsolationLevel);
}
setCatalog(oldCatalog);
setReadOnly(oldReadOnly);
}
return;
} catch (Exception EEE) {
if (EEE instanceof SQLException && ((SQLException) EEE).getErrorCode() == MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD
&& !getDisconnectOnExpiredPasswords()) {
return;
}
if (this.io != null) {
this.io.forceClose();
}
connectionNotEstablishedBecause = EEE;
if (EEE instanceof SQLException) {
throw (SQLException) EEE;
}
SQLException chainedEx = SQLError.createSQLException(Messages.getString("Connection.UnableToConnect"),
SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE, getExceptionInterceptor());
chainedEx.initCause(connectionNotEstablishedBecause);
throw chainedEx;
}
}
private void createPreparedStatementCaches() throws SQLException {
synchronized (getConnectionMutex()) {
int cacheSize = getPreparedStatementCacheSize();
try {
Class> factoryClass;
factoryClass = Class.forName(getParseInfoCacheFactory());
@SuppressWarnings("unchecked")
CacheAdapterFactory cacheFactory = ((CacheAdapterFactory) factoryClass.newInstance());
this.cachedPreparedStatementParams = cacheFactory.getInstance(this, this.myURL, getPreparedStatementCacheSize(),
getPreparedStatementCacheSqlLimit(), this.props);
} catch (ClassNotFoundException e) {
SQLException sqlEx = SQLError.createSQLException(
Messages.getString("Connection.CantFindCacheFactory", new Object[] { getParseInfoCacheFactory(), "parseInfoCacheFactory" }),
getExceptionInterceptor());
sqlEx.initCause(e);
throw sqlEx;
} catch (InstantiationException e) {
SQLException sqlEx = SQLError.createSQLException(
Messages.getString("Connection.CantLoadCacheFactory", new Object[] { getParseInfoCacheFactory(), "parseInfoCacheFactory" }),
getExceptionInterceptor());
sqlEx.initCause(e);
throw sqlEx;
} catch (IllegalAccessException e) {
SQLException sqlEx = SQLError.createSQLException(
Messages.getString("Connection.CantLoadCacheFactory", new Object[] { getParseInfoCacheFactory(), "parseInfoCacheFactory" }),
getExceptionInterceptor());
sqlEx.initCause(e);
throw sqlEx;
}
if (getUseServerPreparedStmts()) {
this.serverSideStatementCheckCache = new LRUCache(cacheSize);
this.serverSideStatementCache = new LRUCache(cacheSize) {
private static final long serialVersionUID = 7692318650375988114L;
@Override
protected boolean removeEldestEntry(java.util.Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy