Bug#857128: unblock: mysql-connector-java/5.1.41-1
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Hi,
This is a pre-upload request to update the mysql-connector-java package
to the version 5.1.41-1 in stretch. This is a bug fix release (upstream
moved to the version 6.x last year, and the 5.1.x branch is now receiving
only important bug fixes).
Thank you,
Emmanuel Bourg
unblock mysql-connector-java/5.1.41-1
diff --git a/CHANGES b/CHANGES
index abefb8f..bdbbcbd 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,32 @@
# Changelog
# $Id$
+02-28-17 - Version 5.1.41
+
+ - Fix for Bug#25517837, CONNECT PERFORMNACE DEGRADED BY 10% IN 5.1.41.
+
+ - Fix for Bug#25504578, CONNECT FAILS WHEN CONNECTIONCOLLATION=ISO-8859-13.
+
+ - Fix for Bug#25438355, Improper automatic deserialization of binary data.
+
+ - Fix for Bug#70785 (17756825), MySQL Connector/J inconsistent init state for autocommit.
+ Property 'elideSetAutoCommits' is temporarily disabled due to Bug#66884. Defaults to 'false' until this bug is fixed.
+
+ - Fix for Bug#75615 (21181249), Incorrect implementation of Connection.setNetworkTimeout().
+
+ - Fix for Bug#81706 (23535001), NullPointerException in driver.
+
+ - Fix for Bug#81108 (23264511), FabricMySQLConnectionProxy.setShardTable method logic miss.
+
+ - Fix for Bug#83052 (25048543), static method in com.mysql.jdbc.Util relies on null object.
+
+ - Fix for Bug#82203 (24289730), com.mysql.fabric.HashShardMapping is not thread safe.
+
+ - Updated collations map.
+
+ - Fix for Bug#69526 (17035755), 'Abandoned connection cleanup thread' at mysql-connector-java-5.1.25.
+
+ - Fix for Bug#82826 (24942672), Unneeded version requirement for javax.net.ssl Import-Package on OSGi MANIFEST.MF.
+
09-30-16 - Version 5.1.40
- Fix for Bug#24619829, NEW FAILURES IN C/JAVA UNITTESTS AGAINST MYSQL 8.0.
diff --git a/README b/README
index bacea06..2c05dee 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-MySQL Connector/J 5.1.40
+MySQL Connector/J 5.1.41
This is a release of MySQL Connector/J, Oracle's dual-
license JDBC Driver for MySQL. For the avoidance of
@@ -6,7 +6,7 @@ doubt, this particular copy of the software is released
under the version 2 of the GNU General Public License.
MySQL Connector/J is brought to you by Oracle.
-Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
License information can be found in the COPYING file.
diff --git a/README.txt b/README.txt
index ee5417f..9e93489 100644
--- a/README.txt
+++ b/README.txt
@@ -1,4 +1,4 @@
-MySQL Connector/J 5.1.40
+MySQL Connector/J 5.1.41
This is a release of MySQL Connector/J, Oracle's dual-
license JDBC Driver for MySQL. For the avoidance of
@@ -6,7 +6,7 @@ doubt, this particular copy of the software is released
under the version 2 of the GNU General Public License.
MySQL Connector/J is brought to you by Oracle.
-Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
License information can be found in the COPYING file.
diff --git a/build.xml b/build.xml
index 8ff3fa1..4edd5ca 100644
--- a/build.xml
+++ b/build.xml
@@ -158,7 +158,7 @@ com.mysql.jdbc.noCleanBetweenCompiles=yes
<property name="major_version" value="5" />
<property name="minor_version" value="1" />
- <property name="subminor_version" value="40" />
+ <property name="subminor_version" value="41" />
<property name="version_status" value="" />
<property name="version" value="${major_version}.${minor_version}.${subminor_version}${version_status}" />
@@ -209,7 +209,7 @@ com.mysql.jdbc.noCleanBetweenCompiles=yes
<!-- Java compiler arguments to widen warnings detection and fail on warnings. -->
<condition property="javac.compilerarg" value="-Xlint:all -Werror" else="">
- <isset property="com.mysql.jdbc.failOnWarnings"/>
+ <isset property="com.mysql.jdbc.failOnWarnings" />
</condition>
<!-- Classpaths settings. -->
@@ -629,32 +629,33 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<property name="osgid-version" value="${major_version}.${minor_version}.${subminor_version}" />
- <property name="jee-imports"
- value="javax.naming,javax.naming.spi,javax.sql,javax.transaction.xa;version="[1.0.1, 2.0.0)";resolution:=optional" />
- <property name="crypto-imports" value="javax.net,javax.net.ssl;version="[1.0.1, 2.0.0)";resolution:=optional" />
+ <property name="crypto-imports" value="javax.net.ssl;javax.crypto;resolution:=optional" />
<property name="jdbc4-imports"
- value="javax.xml.parsers, javax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.sax,javax.xml.transform.stax,javax.xml.transform.stream,org.w3c.dom,org.xml.sax,org.xml.sax.helpers;resolution:=optional" />
+ value="javax.xml.parsers;javax.xml.stream;javax.xml.transform;javax.xml.transform.dom;javax.xml.transform.sax;javax.xml.transform.stax;javax.xml.transform.stream;org.w3c.dom;org.xml.sax;org.xml.sax.helpers;resolution:=optional" />
+ <property name="jee-imports" value="javax.sql;javax.naming;javax.naming.spi;javax.transaction.xa;resolution:=optional" />
+ <property name="jmx-imports" value="javax.management;resolution:=optional" />
<property name="integration-imports"
- value="com.mchange.v2.c3p0;version="[0.9.1.2, 1.0.0)";resolution:=optional,org.jboss.resource.adapter.jdbc;resolution:=optional,org.jboss.resource.adapter.jdbc.vendor;resolution:=optional" />
+ value="com.mchange.v2.c3p0;version="[0.9.1.2,1.0.0)";resolution:=optional,org.jboss.resource.adapter.jdbc;org.jboss.resource.adapter.jdbc.vendor;resolution:=optional" />
+ <property name="logging-imports" value="org.slf4j;resolution:=optional" />
+ <property name="fabric-imports"
+ value="javax.xml.datatype;org.hibernate;org.hibernate.cfg;org.hibernate.service;org.hibernate.service.jdbc.connections.spi;resolution:=optional" />
<property name="driver-exports"
- value="com.mysql.jdbc;version="${osgid-version}";uses:="com.mysql.jdbc.log,javax.naming,javax.net.ssl,javax.xml.transform,org.xml.sax"" />
+ value="com.mysql.jdbc;version="${osgid-version}";uses:="com.mysql.jdbc.log,javax.management,javax.naming,javax.net.ssl,javax.xml.parsers,javax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.sax,javax.xml.transform.stax,javax.xml.transform.stream,org.xml.sax"" />
<property name="jee-exports"
- value="com.mysql.jdbc.jdbc2.optional;version="${osgid-version}";uses:="com.mysql.jdbc,com.mysql.jdbc.log,javax.naming,javax.sql,javax.transaction.xa"" />
+ value="com.mysql.jdbc.jdbc2.optional;version="${osgid-version}";uses:="com.mysql.jdbc,com.mysql.jdbc.log,javax.sql,javax.naming,javax.naming.spi,javax.transaction.xa"" />
<property name="logging-exports" value="com.mysql.jdbc.log;version="${osgid-version}"" />
- <property name="profiling-exports" value="com.mysql.jdbc.profiler;version="${osgid-version}";uses:="com.mysql.jdbc"" />
- <property name="util-exports" value="com.mysql.jdbc.util;version="${osgid-version}";uses:="com.mysql.jdbc.log"" />
+ <property name="profiling-exports" value="com.mysql.jdbc.profiler;version="${osgid-version}"" />
+ <property name="util-exports" value="com.mysql.jdbc.util;version="${osgid-version}"" />
<property name="exceptions-exports" value="com.mysql.jdbc.exceptions;version="${osgid-version}"" />
- <property name="jdbc4-exceptions-exports"
- value="com.mysql.jdbc.exceptions.jdbc4;version="${osgid-version}";uses:="com.mysql.jdbc"" />
- <property name="fabric-exports"
- value="com.mysql.fabric.jdbc;version="${osgid-version}";uses:="com.mysql.jdbc"" />
-
- <property name="interceptors-exports" value="com.mysql.jdbc.interceptors;version="${osgid-version}";uses:="com.mysql.jdbc"" />
+ <property name="jdbc4-exceptions-exports" value="com.mysql.jdbc.exceptions.jdbc4;version="${osgid-version}"" />
+ <property name="interceptors-exports" value="com.mysql.jdbc.interceptors;version="${osgid-version}"" />
<property name="integration-exports"
- value="com.mysql.jdbc.integration.c3p0;version="${osgid-version}",com.mysql.jdbc.integration.jboss;version="${osgid-version}"" />
+ value="com.mysql.jdbc.integration.c3p0;version="${osgid-version}";uses:="com.mchange.v2.c3p0",com.mysql.jdbc.integration.jboss;version="${osgid-version}";uses:="org.jboss.resource.adapter.jdbc,org.jboss.resource.adapter.jdbc.vendor"" />
<property name="configs-exports" value="com.mysql.jdbc.configs;version="${osgid-version}"" />
- <property name="legacy-exports" value="org.gjt.mm.mysql;version="${osgid-version}"" />
+ <property name="legacy-exports" value="org.gjt.mm.mysql;version="${osgid-version}";uses:="com.mysql.jdbc"" />
+ <property name="fabric-exports"
+ value="com.mysql.fabric;com.mysql.fabric.hibernate;com.mysql.fabric.jdbc;version="${osgid-version}";uses:="com.mysql.jdbc,javax.xml.datatype;org.hibernate;org.hibernate.cfg;org.hibernate.service;org.hibernate.service.jdbc.connections.spi"" />
<manifest file="${buildDir}/${fullProdName}/META-INF/MANIFEST.MF">
<attribute name="Built-By" value="${user.name}" />
@@ -668,14 +669,15 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<!-- OSGi -->
<attribute name="Bundle-Vendor" value="Oracle Corporation" />
- <attribute name="Bundle-Classpath" value="." />
+ <attribute name="Bundle-ClassPath" value="." />
<attribute name="Bundle-Version" value="${osgid-version}" />
<attribute name="Bundle-Name" value="Oracle Corporation's JDBC Driver for MySQL" />
<attribute name="Bundle-ManifestVersion" value="2" />
<attribute name="Bundle-SymbolicName" value="com.mysql.jdbc" />
<attribute name="Export-Package"
value="${driver-exports},${jee-exports},${logging-exports},${profiling-exports},${util-exports},${exceptions-exports},${jdbc4-exceptions-exports},${interceptors-exports},${integration-exports},${configs-exports},${legacy-exports},${fabric-exports}" />
- <attribute name="Import-Package" value="${crypto-imports},${jdbc4-imports},${jee-imports},${integration-imports}" />
+ <attribute name="Import-Package"
+ value="${crypto-imports},${jdbc4-imports},${jee-imports},${jmx-imports},${integration-imports},${logging-imports},${fabric-imports}" />
</manifest>
<jar jarfile="${buildDir}/${fullProdName}/${fullProdName}-bin.jar"
@@ -1186,8 +1188,8 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<syspropertyset refid="junit.system.properties" />
<sysproperty key="com.mysql.jdbc.testsuite.url" value="${com.mysql.jdbc.testsuite.url.final}" />
- <sysproperty key="jcov.template" value="${com.mysql.jdbc.coverage.result.dir.final}/template.xml"/>
- <sysproperty key="jcov.file" value="${com.mysql.jdbc.coverage.result.dir.final}/${com.mysql.jdbc.coverage.result.name.final}"/>
+ <sysproperty key="jcov.template" value="${com.mysql.jdbc.coverage.result.dir.final}/template.xml" />
+ <sysproperty key="jcov.file" value="${com.mysql.jdbc.coverage.result.dir.final}/${com.mysql.jdbc.coverage.result.name.final}" />
<classpath>
<pathelement location="${com.mysql.jdbc.extra.libs}/jcov/jcov_file_saver.jar" />
@@ -1238,8 +1240,8 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<syspropertyset refid="junit.system.properties" />
<sysproperty key="com.mysql.jdbc.testsuite.url" value="${com.mysql.jdbc.testsuite.url.final}" />
- <sysproperty key="jcov.template" value="${com.mysql.jdbc.coverage.result.dir.final}/template.xml"/>
- <sysproperty key="jcov.file" value="${com.mysql.jdbc.coverage.result.dir.final}/${com.mysql.jdbc.coverage.result.name.final}"/>
+ <sysproperty key="jcov.template" value="${com.mysql.jdbc.coverage.result.dir.final}/template.xml" />
+ <sysproperty key="jcov.file" value="${com.mysql.jdbc.coverage.result.dir.final}/${com.mysql.jdbc.coverage.result.name.final}" />
<classpath>
<pathelement location="${com.mysql.jdbc.extra.libs}/jcov/jcov_file_saver.jar" />
@@ -1283,8 +1285,8 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<syspropertyset refid="junit.system.properties" />
<sysproperty key="com.mysql.jdbc.testsuite.url" value="${com.mysql.jdbc.testsuite.url.final}" />
- <sysproperty key="jcov.template" value="${com.mysql.jdbc.coverage.result.dir.final}/template.xml"/>
- <sysproperty key="jcov.file" value="${com.mysql.jdbc.coverage.result.dir.final}/${com.mysql.jdbc.coverage.result.name.final}"/>
+ <sysproperty key="jcov.template" value="${com.mysql.jdbc.coverage.result.dir.final}/template.xml" />
+ <sysproperty key="jcov.file" value="${com.mysql.jdbc.coverage.result.dir.final}/${com.mysql.jdbc.coverage.result.name.final}" />
<classpath>
<pathelement location="${com.mysql.jdbc.extra.libs}/jcov/jcov_file_saver.jar" />
@@ -1462,13 +1464,13 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<!-- ********************************* -->
- <target name="test-coverage" depends="-jcov-instrument, test" description="Runs tests collecting coverage results."/>
+ <target name="test-coverage" depends="-jcov-instrument, test" description="Runs tests collecting coverage results." />
<target name="-jcov-instrument" depends="compile-driver, -set-test-coverage-detaults">
- <mkdir dir="${buildDir}/${fullProdName}-instr"/>
- <mkdir dir="${com.mysql.jdbc.coverage.result.dir.final}"/>
- <delete file="${com.mysql.jdbc.coverage.result.dir.final}/template.xml"/>
+ <mkdir dir="${buildDir}/${fullProdName}-instr" />
+ <mkdir dir="${com.mysql.jdbc.coverage.result.dir.final}" />
+ <delete file="${com.mysql.jdbc.coverage.result.dir.final}/template.xml" />
<java fork="true" jvm="${com.mysql.jdbc.jdk8}/bin/java" classname="com.sun.tdk.jcov.Instr" classpathref="project.build.classpath">
<arg line="-e testsuite.* -e demo.* -t ${com.mysql.jdbc.coverage.result.dir.final}/template.xml -output ${buildDir}/${fullProdName}-instr ${buildDir}/${fullProdName}" />
@@ -1492,7 +1494,7 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<target name="report-coverage" depends="-jcov-merge, -set-report-coverage-detaults" description="Merges coverage results and creates HTML coverage report.">
- <mkdir dir="${com.mysql.jdbc.coverage.report.dir.final}"/>
+ <mkdir dir="${com.mysql.jdbc.coverage.report.dir.final}" />
<java fork="true" jvm="${com.mysql.jdbc.jdk8}/bin/java" classname="com.sun.tdk.jcov.RepGen" classpathref="project.build.classpath">
<arg line="-e testsuite.* -e demo.* -src ${sourceDir} -o ${com.mysql.jdbc.coverage.report.dir.final} ${com.mysql.jdbc.coverage.merge.result.final}" />
</java>
@@ -1507,10 +1509,14 @@ Java 8 (for JDBC 4+ implementation) is also required. Set the full path to this
<target name="-set-report-coverage-detaults" depends="-set-test-coverage-detaults">
- <condition property="com.mysql.jdbc.coverage.merge.result.final" value="${com.mysql.jdbc.coverage.merge.result}" else="${com.mysql.jdbc.coverage.result.dir.final}/result.xml">
+ <condition property="com.mysql.jdbc.coverage.merge.result.final"
+ value="${com.mysql.jdbc.coverage.merge.result}"
+ else="${com.mysql.jdbc.coverage.result.dir.final}/result.xml">
<isset property="com.mysql.jdbc.coverage.merge.result" />
</condition>
- <condition property="com.mysql.jdbc.coverage.report.dir.final" value="${com.mysql.jdbc.coverage.report.dir}" else="${com.mysql.jdbc.coverage.result.dir.final}/report">
+ <condition property="com.mysql.jdbc.coverage.report.dir.final"
+ value="${com.mysql.jdbc.coverage.report.dir}"
+ else="${com.mysql.jdbc.coverage.result.dir.final}/report">
<isset property="com.mysql.jdbc.coverage.report.dir" />
</condition>
</target>
diff --git a/debian/changelog b/debian/changelog
index e20c0be..33f2ba3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+mysql-connector-java (5.1.41-1) unstable; urgency=medium
+
+ * Team upload.
+ * New upstream release
+ - Refreshed the patches
+
+ -- Emmanuel Bourg <ebourg@apache.org> Wed, 08 Mar 2017 10:53:22 +0100
+
mysql-connector-java (5.1.40-1) unstable; urgency=medium
* Team upload.
diff --git a/debian/patches/0001-disable-testsuite.patch b/debian/patches/0001-disable-testsuite.patch
index 9015e7b..3f8c393 100644
--- a/debian/patches/0001-disable-testsuite.patch
+++ b/debian/patches/0001-disable-testsuite.patch
@@ -8,7 +8,7 @@ Subject: [PATCH] disable testsuite
--- a/build.xml
+++ b/build.xml
-@@ -833,7 +833,7 @@
+@@ -835,7 +835,7 @@
<!-- Compile the driver including JDBC 3 and JDBC 4+ implementations, JUnit test suite and 'helpers' for third-party software. -->
<target name="compile"
description="Compiles driver including JDBC 3 and JDBC 4+ implementations, JUnit test suite and integration 'helpers' for third-party software."
diff --git a/debian/patches/0002-java6-compilation-compat.patch b/debian/patches/0002-java6-compilation-compat.patch
index e445743..b6a6471 100644
--- a/debian/patches/0002-java6-compilation-compat.patch
+++ b/debian/patches/0002-java6-compilation-compat.patch
@@ -25,7 +25,7 @@ Subject: [PATCH] Java 8 compatibility
--- a/src/com/mysql/fabric/jdbc/FabricMySQLConnectionProxy.java
+++ b/src/com/mysql/fabric/jdbc/FabricMySQLConnectionProxy.java
-@@ -3050,4 +3050,36 @@
+@@ -3065,4 +3065,36 @@
public void decachePreparedStatement(ServerPreparedStatement pstmt) throws SQLException {
}
@@ -169,9 +169,9 @@ Subject: [PATCH] Java 8 compatibility
*/
--- a/src/com/mysql/jdbc/ConnectionImpl.java
+++ b/src/com/mysql/jdbc/ConnectionImpl.java
-@@ -5550,4 +5550,56 @@
- public void setProfilerEventHandlerInstance(ProfilerEventHandler h) {
- this.eventSink = h;
+@@ -5507,4 +5507,56 @@
+ }
+ }
}
+
+ public java.sql.Clob createClob() throws SQLException {
@@ -312,7 +312,7 @@ Subject: [PATCH] Java 8 compatibility
}
--- a/src/com/mysql/jdbc/NonRegisteringDriver.java
+++ b/src/com/mysql/jdbc/NonRegisteringDriver.java
-@@ -906,4 +906,9 @@
+@@ -908,4 +908,9 @@
}
}
}
@@ -324,7 +324,7 @@ Subject: [PATCH] Java 8 compatibility
}
--- a/src/com/mysql/jdbc/PreparedStatement.java
+++ b/src/com/mysql/jdbc/PreparedStatement.java
-@@ -5090,6 +5090,18 @@
+@@ -5096,6 +5096,18 @@
&& StringUtils.indexOfIgnoreCase(statementStartPos, sql, "SELECT", "\"'`", "\"'`", StringUtils.SEARCH_MODE__MRK_COM_WS) == -1;
}
@@ -345,7 +345,7 @@ Subject: [PATCH] Java 8 compatibility
* Same as PreparedStatement.executeUpdate() but returns long instead of int.
--- a/src/com/mysql/jdbc/ResultSetImpl.java
+++ b/src/com/mysql/jdbc/ResultSetImpl.java
-@@ -7906,4 +7906,200 @@
+@@ -7908,4 +7908,200 @@
protected ExceptionInterceptor getExceptionInterceptor() {
return this.exceptionInterceptor;
}
diff --git a/debian/patches/0003-disable-hibernate-fabric.patch b/debian/patches/0003-disable-hibernate-fabric.patch
index 130355b..3d01023 100644
--- a/debian/patches/0003-disable-hibernate-fabric.patch
+++ b/debian/patches/0003-disable-hibernate-fabric.patch
@@ -19,7 +19,7 @@ Forwarded: not-needed
</target>
-@@ -887,8 +889,10 @@
+@@ -889,8 +891,10 @@
bootclasspath="${com.mysql.jdbc.jre6.rtjar}"
source="1.6"
target="1.6">
diff --git a/src/com/mysql/fabric/HashShardMapping.java b/src/com/mysql/fabric/HashShardMapping.java
index 6a6632c..5b3b3bd 100644
--- a/src/com/mysql/fabric/HashShardMapping.java
+++ b/src/com/mysql/fabric/HashShardMapping.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -60,7 +60,10 @@ public class HashShardMapping extends ShardMapping {
@Override
protected ShardIndex getShardIndexForKey(String stringKey) {
- String hashedKey = new BigInteger(/* unsigned/positive */1, md5Hasher.digest(stringKey.getBytes())).toString(16).toUpperCase();
+ String hashedKey;
+ synchronized (md5Hasher) {
+ hashedKey = new BigInteger(/* unsigned/positive */1, md5Hasher.digest(stringKey.getBytes())).toString(16).toUpperCase();
+ }
// pad out to 32 digits
for (int i = 0; i < (32 - hashedKey.length()); ++i) {
diff --git a/src/com/mysql/fabric/jdbc/FabricMySQLConnectionProxy.java b/src/com/mysql/fabric/jdbc/FabricMySQLConnectionProxy.java
index f613df0..868b4f8 100644
--- a/src/com/mysql/fabric/jdbc/FabricMySQLConnectionProxy.java
+++ b/src/com/mysql/fabric/jdbc/FabricMySQLConnectionProxy.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -138,6 +138,7 @@ public class FabricMySQLConnectionProxy extends ConnectionPropertiesImpl impleme
private static final Set<String> replConnGroupLocks = Collections.synchronizedSet(new HashSet<String>());
private static final Class<?> JDBC4_NON_TRANSIENT_CONN_EXCEPTION;
+
static {
Class<?> clazz = null;
try {
@@ -337,8 +338,8 @@ public class FabricMySQLConnectionProxy extends ConnectionPropertiesImpl impleme
String db = this.database;
if (shardTable.contains(".")) {
String pair[] = shardTable.split("\\.");
- table = pair[0];
- db = pair[1];
+ db = pair[0];
+ table = pair[1];
}
this.shardMapping = this.fabricConnection.getShardMapping(db, table);
if (this.shardMapping == null) {
@@ -2957,6 +2958,10 @@ public class FabricMySQLConnectionProxy extends ConnectionPropertiesImpl impleme
return getActiveMySQLConnectionPassive().lowerCaseTableNames();
}
+ /**
+ *
+ * @param stmt
+ */
public void maxRowsChanged(com.mysql.jdbc.Statement stmt) {
}
@@ -2998,6 +3003,11 @@ public class FabricMySQLConnectionProxy extends ConnectionPropertiesImpl impleme
public void unregisterStatement(com.mysql.jdbc.Statement stmt) {
}
+ /**
+ *
+ * @param stmt
+ * @throws SQLException
+ */
public void unsetMaxRows(com.mysql.jdbc.Statement stmt) throws SQLException {
}
@@ -3017,6 +3027,11 @@ public class FabricMySQLConnectionProxy extends ConnectionPropertiesImpl impleme
return null;
}
+ /**
+ *
+ * @param name
+ * @return
+ */
public String getClientInfo(String name) {
return null;
}
diff --git a/src/com/mysql/jdbc/AbandonedConnectionCleanupThread.java b/src/com/mysql/jdbc/AbandonedConnectionCleanupThread.java
index 8da014e..80bdb3f 100644
--- a/src/com/mysql/jdbc/AbandonedConnectionCleanupThread.java
+++ b/src/com/mysql/jdbc/AbandonedConnectionCleanupThread.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -24,23 +24,44 @@
package com.mysql.jdbc;
import java.lang.ref.Reference;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
import com.mysql.jdbc.NonRegisteringDriver.ConnectionPhantomReference;
-public class AbandonedConnectionCleanupThread extends Thread {
- private static boolean running = true;
- private static Thread threadRef = null;
+/**
+ * This class implements a thread that is responsible for closing abandoned MySQL connections, i.e., connections that are not explicitly closed.
+ * There is only one instance of this class and there is a single thread to do this task. This thread's executor is statically referenced in this same class.
+ */
+public class AbandonedConnectionCleanupThread implements Runnable {
+ private static final ExecutorService cleanupThreadExcecutorService;
+ static Thread threadRef = null;
+
+ static {
+ cleanupThreadExcecutorService = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r, "Abandoned connection cleanup thread");
+ t.setDaemon(true);
+ // Tie the thread's context ClassLoader to the ClassLoader that loaded the class instead of inheriting the context ClassLoader from the current
+ // thread, which would happen by default.
+ // Application servers may use this information if they attempt to shutdown this thread. By leaving the default context ClassLoader this thread
+ // could end up being shut down even when it is shared by other applications and, being it statically initialized, thus, never restarted again.
+ t.setContextClassLoader(AbandonedConnectionCleanupThread.class.getClassLoader());
+ return threadRef = t;
+ }
+ });
+ cleanupThreadExcecutorService.execute(new AbandonedConnectionCleanupThread());
+ }
- public AbandonedConnectionCleanupThread() {
- super("Abandoned connection cleanup thread");
+ private AbandonedConnectionCleanupThread() {
}
- @Override
public void run() {
- threadRef = this;
- while (running) {
+ for (;;) {
try {
- Reference<? extends ConnectionImpl> ref = NonRegisteringDriver.refQueue.remove(100);
+ checkContextClassLoaders();
+ Reference<? extends ConnectionImpl> ref = NonRegisteringDriver.refQueue.remove(5000);
if (ref != null) {
try {
((ConnectionPhantomReference) ref).cleanup();
@@ -49,19 +70,78 @@ public class AbandonedConnectionCleanupThread extends Thread {
}
}
+ } catch (InterruptedException e) {
+ threadRef = null;
+ return;
+
} catch (Exception ex) {
- // no where to really log this if we're static
+ // Nowhere to really log this.
}
}
}
- public static void shutdown() throws InterruptedException {
- running = false;
- if (threadRef != null) {
- threadRef.interrupt();
- threadRef.join();
- threadRef = null;
+ /**
+ * Checks if the thread's context ClassLoader is active. This is usually true but some application managers implement a life-cycle mechanism in their
+ * ClassLoaders that is linked to the corresponding application's life-cycle. As such, a stopped/ended application will have a ClassLoader unable to load
+ * anything and, eventually, they throw an exception when trying to do so. When this happens, this thread has no point in being alive anymore.
+ */
+ private void checkContextClassLoaders() {
+ try {
+ threadRef.getContextClassLoader().getResource("");
+ } catch (Throwable e) {
+ // Shutdown no matter what.
+ uncheckedShutdown();
}
}
+ /**
+ * Checks if the context ClassLoaders from this and the caller thread are the same.
+ *
+ * @return true if both threads share the same context ClassLoader, false otherwise
+ */
+ private static boolean consistentClassLoaders() {
+ ClassLoader callerCtxClassLoader = Thread.currentThread().getContextClassLoader();
+ ClassLoader threadCtxClassLoader = threadRef.getContextClassLoader();
+ return callerCtxClassLoader != null && threadCtxClassLoader != null && callerCtxClassLoader == threadCtxClassLoader;
+ }
+
+ /**
+ * Performs a checked shutdown, i.e., the context ClassLoaders from this and the caller thread are checked for consistency prior to performing the shutdown
+ * operation.
+ */
+ public static void checkedShutdown() {
+ shutdown(true);
+ }
+
+ /**
+ * Performs an unchecked shutdown, i.e., the shutdown is performed independently of the context ClassLoaders from the involved threads.
+ */
+ public static void uncheckedShutdown() {
+ shutdown(false);
+ }
+
+ /**
+ * Shuts down this thread either checking or not the context ClassLoaders from the involved threads.
+ *
+ * @param checked
+ * does a checked shutdown if true, unchecked otherwise
+ */
+ private static void shutdown(boolean checked) {
+ if (checked && !consistentClassLoaders()) {
+ // This thread can't be shutdown from the current thread's context ClassLoader. Doing so would most probably prevent from restarting this thread
+ // later on. An unchecked shutdown can still be done if needed by calling shutdown(false).
+ return;
+ }
+ cleanupThreadExcecutorService.shutdownNow();
+ }
+
+ /**
+ * Shuts down this thread.
+ *
+ * @deprecated use {@link #checkedShutdown()} instead.
+ */
+ @Deprecated
+ public static void shutdown() {
+ checkedShutdown();
+ }
}
diff --git a/src/com/mysql/jdbc/CharsetMapping.java b/src/com/mysql/jdbc/CharsetMapping.java
index 7851f07..a720daf 100644
--- a/src/com/mysql/jdbc/CharsetMapping.java
+++ b/src/com/mysql/jdbc/CharsetMapping.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -42,7 +42,7 @@ import java.util.TreeMap;
*/
public class CharsetMapping {
- public static final int MAP_SIZE = 255; // Size of static maps
+ public static final int MAP_SIZE = 2048; // Size of static maps
public static final String[] COLLATION_INDEX_TO_COLLATION_NAME;
public static final MysqlCharset[] COLLATION_INDEX_TO_CHARSET;
@@ -120,7 +120,8 @@ public class CharsetMapping {
private static final String MYSQL_4_0_CHARSET_NAME_win1251 = "win1251"; // 4.1 => 17 (removed)
private static final String MYSQL_4_0_CHARSET_NAME_win1251ukr = "win1251ukr"; // 4.1 => 23 cp1251 cp1251_ukrainian_ci
- private static final String NOT_USED = MYSQL_CHARSET_NAME_latin1; // punting for not-used character sets
+ public static final String NOT_USED = MYSQL_CHARSET_NAME_latin1; // punting for not-used character sets
+ public static final String COLLATION_NOT_DEFINED = "none";
public static final int MYSQL_COLLATION_INDEX_utf8 = 33;
public static final int MYSQL_COLLATION_INDEX_binary = 63;
@@ -256,94 +257,37 @@ public class CharsetMapping {
// complete list of mysql collations and their corresponding character sets each element of collation[1]..collation[MAP_SIZE-1] must not be null
Collation[] collation = new Collation[MAP_SIZE];
collation[1] = new Collation(1, "big5_chinese_ci", 1, MYSQL_CHARSET_NAME_big5);
- collation[84] = new Collation(84, "big5_bin", 0, MYSQL_CHARSET_NAME_big5);
-
collation[2] = new Collation(2, "latin2_czech_cs", 0, MYSQL_CHARSET_NAME_latin2);
- collation[9] = new Collation(9, "latin2_general_ci", 1, MYSQL_CHARSET_NAME_latin2);
- collation[21] = new Collation(21, "latin2_hungarian_ci", 0, MYSQL_CHARSET_NAME_latin2);
- collation[27] = new Collation(27, "latin2_croatian_ci", 0, MYSQL_CHARSET_NAME_latin2);
- collation[77] = new Collation(77, "latin2_bin", 0, MYSQL_CHARSET_NAME_latin2);
-
+ collation[3] = new Collation(3, "dec8_swedish_ci", 0, MYSQL_CHARSET_NAME_dec8);
collation[4] = new Collation(4, "cp850_general_ci", 1, MYSQL_CHARSET_NAME_cp850);
- collation[80] = new Collation(80, "cp850_bin", 0, MYSQL_CHARSET_NAME_cp850);
-
collation[5] = new Collation(5, "latin1_german1_ci", 1, MYSQL_CHARSET_NAME_latin1);
- collation[8] = new Collation(8, "latin1_swedish_ci", 0, MYSQL_CHARSET_NAME_latin1);
- collation[15] = new Collation(15, "latin1_danish_ci", 0, MYSQL_CHARSET_NAME_latin1);
- collation[31] = new Collation(31, "latin1_german2_ci", 0, MYSQL_CHARSET_NAME_latin1);
- collation[47] = new Collation(47, "latin1_bin", 0, MYSQL_CHARSET_NAME_latin1);
- collation[48] = new Collation(48, "latin1_general_ci", 0, MYSQL_CHARSET_NAME_latin1);
- collation[49] = new Collation(49, "latin1_general_cs", 0, MYSQL_CHARSET_NAME_latin1);
- collation[76] = new Collation(76, "not_implemented", 0, NOT_USED);
- collation[94] = new Collation(94, "latin1_spanish_ci", 0, MYSQL_CHARSET_NAME_latin1);
- collation[100] = new Collation(100, "not_implemented", 0, NOT_USED);
- collation[125] = new Collation(125, "not_implemented", 0, NOT_USED);
- collation[126] = new Collation(126, "not_implemented", 0, NOT_USED);
- collation[127] = new Collation(127, "not_implemented", 0, NOT_USED);
- collation[152] = new Collation(152, "not_implemented", 0, NOT_USED);
- collation[153] = new Collation(153, "not_implemented", 0, NOT_USED);
- collation[154] = new Collation(154, "not_implemented", 0, NOT_USED);
- collation[155] = new Collation(155, "not_implemented", 0, NOT_USED);
- collation[156] = new Collation(156, "not_implemented", 0, NOT_USED);
- collation[157] = new Collation(157, "not_implemented", 0, NOT_USED);
- collation[158] = new Collation(158, "not_implemented", 0, NOT_USED);
- collation[184] = new Collation(184, "not_implemented", 0, NOT_USED);
- collation[185] = new Collation(185, "not_implemented", 0, NOT_USED);
- collation[186] = new Collation(186, "not_implemented", 0, NOT_USED);
- collation[187] = new Collation(187, "not_implemented", 0, NOT_USED);
- collation[188] = new Collation(188, "not_implemented", 0, NOT_USED);
- collation[189] = new Collation(189, "not_implemented", 0, NOT_USED);
- collation[190] = new Collation(190, "not_implemented", 0, NOT_USED);
- collation[191] = new Collation(191, "not_implemented", 0, NOT_USED);
- collation[216] = new Collation(216, "not_implemented", 0, NOT_USED);
- collation[217] = new Collation(217, "not_implemented", 0, NOT_USED);
- collation[218] = new Collation(218, "not_implemented", 0, NOT_USED);
- collation[219] = new Collation(219, "not_implemented", 0, NOT_USED);
- collation[220] = new Collation(220, "not_implemented", 0, NOT_USED);
- collation[221] = new Collation(221, "not_implemented", 0, NOT_USED);
- collation[222] = new Collation(222, "not_implemented", 0, NOT_USED);
- collation[248] = new Collation(248, "gb18030_chinese_ci", 1, MYSQL_CHARSET_NAME_gb18030);
- collation[249] = new Collation(249, "gb18030_bin", 0, MYSQL_CHARSET_NAME_gb18030);
- collation[250] = new Collation(250, "gb18030_unicode_520_ci", 0, MYSQL_CHARSET_NAME_gb18030);
- collation[251] = new Collation(251, "not_implemented", 0, NOT_USED);
- collation[252] = new Collation(252, "not_implemented", 0, NOT_USED);
- collation[253] = new Collation(253, "not_implemented", 0, NOT_USED);
- collation[254] = new Collation(254, "not_implemented", 0, NOT_USED);
- collation[10] = new Collation(10, "swe7_swedish_ci", 0, MYSQL_CHARSET_NAME_swe7);
- collation[82] = new Collation(82, "swe7_bin", 0, MYSQL_CHARSET_NAME_swe7);
collation[6] = new Collation(6, "hp8_english_ci", 0, MYSQL_CHARSET_NAME_hp8);
- collation[72] = new Collation(72, "hp8_bin", 0, MYSQL_CHARSET_NAME_hp8);
- collation[3] = new Collation(3, "dec8_swedish_ci", 0, MYSQL_CHARSET_NAME_dec8);
- collation[69] = new Collation(69, "dec8_bin", 0, MYSQL_CHARSET_NAME_dec8);
- collation[32] = new Collation(32, "armscii8_general_ci", 0, MYSQL_CHARSET_NAME_armscii8);
- collation[64] = new Collation(64, "armscii8_bin", 0, MYSQL_CHARSET_NAME_armscii8);
- collation[92] = new Collation(92, "geostd8_general_ci", 0, MYSQL_CHARSET_NAME_geostd8);
- collation[93] = new Collation(93, "geostd8_bin", 0, MYSQL_CHARSET_NAME_geostd8);
-
collation[7] = new Collation(7, "koi8r_general_ci", 0, MYSQL_CHARSET_NAME_koi8r);
- collation[74] = new Collation(74, "koi8r_bin", 0, MYSQL_CHARSET_NAME_koi8r);
-
+ collation[8] = new Collation(8, "latin1_swedish_ci", 0, MYSQL_CHARSET_NAME_latin1);
+ collation[9] = new Collation(9, "latin2_general_ci", 1, MYSQL_CHARSET_NAME_latin2);
+ collation[10] = new Collation(10, "swe7_swedish_ci", 0, MYSQL_CHARSET_NAME_swe7);
collation[11] = new Collation(11, "ascii_general_ci", 0, MYSQL_CHARSET_NAME_ascii);
- collation[65] = new Collation(65, "ascii_bin", 0, MYSQL_CHARSET_NAME_ascii);
-
collation[12] = new Collation(12, "ujis_japanese_ci", 0, MYSQL_CHARSET_NAME_ujis);
- collation[91] = new Collation(91, "ujis_bin", 0, MYSQL_CHARSET_NAME_ujis);
-
collation[13] = new Collation(13, "sjis_japanese_ci", 0, MYSQL_CHARSET_NAME_sjis);
collation[14] = new Collation(14, "cp1251_bulgarian_ci", 0, MYSQL_CHARSET_NAME_cp1251);
+ collation[15] = new Collation(15, "latin1_danish_ci", 0, MYSQL_CHARSET_NAME_latin1);
collation[16] = new Collation(16, "hebrew_general_ci", 0, MYSQL_CHARSET_NAME_hebrew);
collation[17] = new Collation(17, "latin1_german1_ci", 0, MYSQL_4_0_CHARSET_NAME_win1251); // removed since 4.1
collation[18] = new Collation(18, "tis620_thai_ci", 0, MYSQL_CHARSET_NAME_tis620);
collation[19] = new Collation(19, "euckr_korean_ci", 0, MYSQL_CHARSET_NAME_euckr);
collation[20] = new Collation(20, "latin7_estonian_cs", 0, MYSQL_CHARSET_NAME_latin7);
+ collation[21] = new Collation(21, "latin2_hungarian_ci", 0, MYSQL_CHARSET_NAME_latin2);
collation[22] = new Collation(22, "koi8u_general_ci", 0, MYSQL_CHARSET_NAME_koi8u);
collation[23] = new Collation(23, "cp1251_ukrainian_ci", 0, MYSQL_CHARSET_NAME_cp1251);
collation[24] = new Collation(24, "gb2312_chinese_ci", 0, MYSQL_CHARSET_NAME_gb2312);
collation[25] = new Collation(25, "greek_general_ci", 0, MYSQL_CHARSET_NAME_greek);
collation[26] = new Collation(26, "cp1250_general_ci", 1, MYSQL_CHARSET_NAME_cp1250);
+ collation[27] = new Collation(27, "latin2_croatian_ci", 0, MYSQL_CHARSET_NAME_latin2);
collation[28] = new Collation(28, "gbk_chinese_ci", 1, MYSQL_CHARSET_NAME_gbk);
collation[29] = new Collation(29, "cp1257_lithuanian_ci", 0, MYSQL_CHARSET_NAME_cp1257);
collation[30] = new Collation(30, "latin5_turkish_ci", 1, MYSQL_CHARSET_NAME_latin5);
+ collation[31] = new Collation(31, "latin1_german2_ci", 0, MYSQL_CHARSET_NAME_latin1);
+ collation[32] = new Collation(32, "armscii8_general_ci", 0, MYSQL_CHARSET_NAME_armscii8);
collation[33] = new Collation(33, "utf8_general_ci", 1, MYSQL_CHARSET_NAME_utf8);
collation[34] = new Collation(34, "cp1250_czech_cs", 0, MYSQL_CHARSET_NAME_cp1250);
collation[35] = new Collation(35, "ucs2_general_ci", 1, MYSQL_CHARSET_NAME_ucs2);
@@ -358,6 +302,9 @@ public class CharsetMapping {
collation[44] = new Collation(44, "cp1250_croatian_ci", 0, MYSQL_CHARSET_NAME_cp1250);
collation[45] = new Collation(45, "utf8mb4_general_ci", 1, MYSQL_CHARSET_NAME_utf8mb4);
collation[46] = new Collation(46, "utf8mb4_bin", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[47] = new Collation(47, "latin1_bin", 0, MYSQL_CHARSET_NAME_latin1);
+ collation[48] = new Collation(48, "latin1_general_ci", 0, MYSQL_CHARSET_NAME_latin1);
+ collation[49] = new Collation(49, "latin1_general_cs", 0, MYSQL_CHARSET_NAME_latin1);
collation[50] = new Collation(50, "cp1251_bin", 0, MYSQL_CHARSET_NAME_cp1251);
collation[51] = new Collation(51, "cp1251_general_ci", 1, MYSQL_CHARSET_NAME_cp1251);
collation[52] = new Collation(52, "cp1251_general_cs", 0, MYSQL_CHARSET_NAME_cp1251);
@@ -372,28 +319,43 @@ public class CharsetMapping {
collation[61] = new Collation(61, "utf32_bin", 0, MYSQL_CHARSET_NAME_utf32);
collation[62] = new Collation(62, "utf16le_bin", 0, MYSQL_CHARSET_NAME_utf16le);
collation[63] = new Collation(63, "binary", 1, MYSQL_CHARSET_NAME_binary);
+ collation[64] = new Collation(64, "armscii8_bin", 0, MYSQL_CHARSET_NAME_armscii8);
+ collation[65] = new Collation(65, "ascii_bin", 0, MYSQL_CHARSET_NAME_ascii);
collation[66] = new Collation(66, "cp1250_bin", 0, MYSQL_CHARSET_NAME_cp1250);
collation[67] = new Collation(67, "cp1256_bin", 0, MYSQL_CHARSET_NAME_cp1256);
collation[68] = new Collation(68, "cp866_bin", 0, MYSQL_CHARSET_NAME_cp866);
+ collation[69] = new Collation(69, "dec8_bin", 0, MYSQL_CHARSET_NAME_dec8);
collation[70] = new Collation(70, "greek_bin", 0, MYSQL_CHARSET_NAME_greek);
collation[71] = new Collation(71, "hebrew_bin", 0, MYSQL_CHARSET_NAME_hebrew);
+ collation[72] = new Collation(72, "hp8_bin", 0, MYSQL_CHARSET_NAME_hp8);
collation[73] = new Collation(73, "keybcs2_bin", 0, MYSQL_CHARSET_NAME_keybcs2);
+ collation[74] = new Collation(74, "koi8r_bin", 0, MYSQL_CHARSET_NAME_koi8r);
collation[75] = new Collation(75, "koi8u_bin", 0, MYSQL_CHARSET_NAME_koi8u);
+ collation[76] = new Collation(76, "utf8_tolower_ci", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[77] = new Collation(77, "latin2_bin", 0, MYSQL_CHARSET_NAME_latin2);
collation[78] = new Collation(78, "latin5_bin", 0, MYSQL_CHARSET_NAME_latin5);
collation[79] = new Collation(79, "latin7_bin", 0, MYSQL_CHARSET_NAME_latin7);
+ collation[80] = new Collation(80, "cp850_bin", 0, MYSQL_CHARSET_NAME_cp850);
collation[81] = new Collation(81, "cp852_bin", 0, MYSQL_CHARSET_NAME_cp852);
+ collation[82] = new Collation(82, "swe7_bin", 0, MYSQL_CHARSET_NAME_swe7);
collation[83] = new Collation(83, "utf8_bin", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[84] = new Collation(84, "big5_bin", 0, MYSQL_CHARSET_NAME_big5);
collation[85] = new Collation(85, "euckr_bin", 0, MYSQL_CHARSET_NAME_euckr);
collation[86] = new Collation(86, "gb2312_bin", 0, MYSQL_CHARSET_NAME_gb2312);
collation[87] = new Collation(87, "gbk_bin", 0, MYSQL_CHARSET_NAME_gbk);
collation[88] = new Collation(88, "sjis_bin", 0, MYSQL_CHARSET_NAME_sjis);
collation[89] = new Collation(89, "tis620_bin", 0, MYSQL_CHARSET_NAME_tis620);
collation[90] = new Collation(90, "ucs2_bin", 0, MYSQL_CHARSET_NAME_ucs2);
+ collation[91] = new Collation(91, "ujis_bin", 0, MYSQL_CHARSET_NAME_ujis);
+ collation[92] = new Collation(92, "geostd8_general_ci", 0, MYSQL_CHARSET_NAME_geostd8);
+ collation[93] = new Collation(93, "geostd8_bin", 0, MYSQL_CHARSET_NAME_geostd8);
+ collation[94] = new Collation(94, "latin1_spanish_ci", 0, MYSQL_CHARSET_NAME_latin1);
collation[95] = new Collation(95, "cp932_japanese_ci", 1, MYSQL_CHARSET_NAME_cp932);
collation[96] = new Collation(96, "cp932_bin", 0, MYSQL_CHARSET_NAME_cp932);
collation[97] = new Collation(97, "eucjpms_japanese_ci", 1, MYSQL_CHARSET_NAME_eucjpms);
collation[98] = new Collation(98, "eucjpms_bin", 0, MYSQL_CHARSET_NAME_eucjpms);
collation[99] = new Collation(99, "cp1250_polish_ci", 0, MYSQL_CHARSET_NAME_cp1250);
+
collation[101] = new Collation(101, "utf16_unicode_ci", 0, MYSQL_CHARSET_NAME_utf16);
collation[102] = new Collation(102, "utf16_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf16);
collation[103] = new Collation(103, "utf16_latvian_ci", 0, MYSQL_CHARSET_NAME_utf16);
@@ -418,6 +380,7 @@ public class CharsetMapping {
collation[122] = new Collation(122, "utf16_croatian_ci", 0, MYSQL_CHARSET_NAME_utf16);
collation[123] = new Collation(123, "utf16_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf16);
collation[124] = new Collation(124, "utf16_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf16);
+
collation[128] = new Collation(128, "ucs2_unicode_ci", 0, MYSQL_CHARSET_NAME_ucs2);
collation[129] = new Collation(129, "ucs2_icelandic_ci", 0, MYSQL_CHARSET_NAME_ucs2);
collation[130] = new Collation(130, "ucs2_latvian_ci", 0, MYSQL_CHARSET_NAME_ucs2);
@@ -442,6 +405,7 @@ public class CharsetMapping {
collation[149] = new Collation(149, "ucs2_croatian_ci", 0, MYSQL_CHARSET_NAME_ucs2);
collation[150] = new Collation(150, "ucs2_unicode_520_ci", 0, MYSQL_CHARSET_NAME_ucs2);
collation[151] = new Collation(151, "ucs2_vietnamese_ci", 0, MYSQL_CHARSET_NAME_ucs2);
+
collation[159] = new Collation(159, "ucs2_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_ucs2);
collation[160] = new Collation(160, "utf32_unicode_ci", 0, MYSQL_CHARSET_NAME_utf32);
collation[161] = new Collation(161, "utf32_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf32);
@@ -467,6 +431,7 @@ public class CharsetMapping {
collation[181] = new Collation(181, "utf32_croatian_ci", 0, MYSQL_CHARSET_NAME_utf32);
collation[182] = new Collation(182, "utf32_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf32);
collation[183] = new Collation(183, "utf32_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf32);
+
collation[192] = new Collation(192, "utf8_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8);
collation[193] = new Collation(193, "utf8_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8);
collation[194] = new Collation(194, "utf8_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8);
@@ -491,6 +456,7 @@ public class CharsetMapping {
collation[213] = new Collation(213, "utf8_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8);
collation[214] = new Collation(214, "utf8_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8);
collation[215] = new Collation(215, "utf8_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8);
+
collation[223] = new Collation(223, "utf8_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_utf8);
collation[224] = new Collation(224, "utf8mb4_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
collation[225] = new Collation(225, "utf8mb4_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
@@ -516,6 +482,78 @@ public class CharsetMapping {
collation[245] = new Collation(245, "utf8mb4_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
collation[246] = new Collation(246, "utf8mb4_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
collation[247] = new Collation(247, "utf8mb4_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[248] = new Collation(248, "gb18030_chinese_ci", 1, MYSQL_CHARSET_NAME_gb18030);
+ collation[249] = new Collation(249, "gb18030_bin", 0, MYSQL_CHARSET_NAME_gb18030);
+ collation[250] = new Collation(250, "gb18030_unicode_520_ci", 0, MYSQL_CHARSET_NAME_gb18030);
+
+ collation[255] = new Collation(255, "utf8mb4_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[256] = new Collation(256, "utf8mb4_de_pb_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[257] = new Collation(257, "utf8mb4_is_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[258] = new Collation(258, "utf8mb4_lv_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[259] = new Collation(259, "utf8mb4_ro_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[260] = new Collation(260, "utf8mb4_sl_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[261] = new Collation(261, "utf8mb4_pl_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[262] = new Collation(262, "utf8mb4_et_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[263] = new Collation(263, "utf8mb4_es_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[264] = new Collation(264, "utf8mb4_sv_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[265] = new Collation(265, "utf8mb4_tr_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[266] = new Collation(266, "utf8mb4_cs_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[267] = new Collation(267, "utf8mb4_da_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[268] = new Collation(268, "utf8mb4_lt_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[269] = new Collation(269, "utf8mb4_sk_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[270] = new Collation(270, "utf8mb4_es_trad_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[271] = new Collation(271, "utf8mb4_la_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+
+ collation[273] = new Collation(273, "utf8mb4_eo_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[274] = new Collation(274, "utf8mb4_hu_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[275] = new Collation(275, "utf8mb4_hr_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+
+ collation[277] = new Collation(277, "utf8mb4_vi_0900_ai_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+
+ collation[278] = new Collation(278, "utf8mb4_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[279] = new Collation(279, "utf8mb4_de_pb_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[280] = new Collation(280, "utf8mb4_is_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[281] = new Collation(281, "utf8mb4_lv_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[282] = new Collation(282, "utf8mb4_ro_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[283] = new Collation(283, "utf8mb4_sl_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[284] = new Collation(284, "utf8mb4_pl_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[285] = new Collation(285, "utf8mb4_et_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[286] = new Collation(286, "utf8mb4_es_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[287] = new Collation(287, "utf8mb4_sv_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[288] = new Collation(288, "utf8mb4_tr_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[289] = new Collation(289, "utf8mb4_cs_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[290] = new Collation(290, "utf8mb4_da_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[291] = new Collation(291, "utf8mb4_lt_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[292] = new Collation(292, "utf8mb4_sk_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[293] = new Collation(293, "utf8mb4_es_trad_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[294] = new Collation(294, "utf8mb4_la_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+
+ collation[296] = new Collation(296, "utf8mb4_eo_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[297] = new Collation(297, "utf8mb4_hu_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[298] = new Collation(298, "utf8mb4_hr_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+
+ collation[300] = new Collation(300, "utf8mb4_vi_0900_as_cs", 0, MYSQL_CHARSET_NAME_utf8mb4);
+
+ collation[326] = new Collation(326, "utf8mb4_test_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+ collation[327] = new Collation(327, "utf16_test_ci", 0, MYSQL_CHARSET_NAME_utf16);
+ collation[328] = new Collation(328, "utf8mb4_test_400_ci", 0, MYSQL_CHARSET_NAME_utf8mb4);
+
+ collation[336] = new Collation(336, "utf8_bengali_standard_ci", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[337] = new Collation(337, "utf8_bengali_traditional_ci", 0, MYSQL_CHARSET_NAME_utf8);
+
+ collation[352] = new Collation(352, "utf8_phone_ci", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[353] = new Collation(353, "utf8_test_ci", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[354] = new Collation(354, "utf8_5624_1", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[355] = new Collation(355, "utf8_5624_2", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[356] = new Collation(356, "utf8_5624_3", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[357] = new Collation(357, "utf8_5624_4", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[358] = new Collation(358, "ucs2_test_ci", 0, MYSQL_CHARSET_NAME_ucs2);
+ collation[359] = new Collation(359, "ucs2_vn_ci", 0, MYSQL_CHARSET_NAME_ucs2);
+ collation[360] = new Collation(360, "ucs2_5624_1", 0, MYSQL_CHARSET_NAME_ucs2);
+
+ collation[368] = new Collation(368, "utf8_5624_5", 0, MYSQL_CHARSET_NAME_utf8);
+ collation[391] = new Collation(391, "utf32_test_ci", 0, MYSQL_CHARSET_NAME_utf32);
+ collation[2047] = new Collation(2047, "utf8_maxuserid_ci", 0, MYSQL_CHARSET_NAME_utf8);
COLLATION_INDEX_TO_COLLATION_NAME = new String[MAP_SIZE];
COLLATION_INDEX_TO_CHARSET = new MysqlCharset[MAP_SIZE];
@@ -523,14 +561,16 @@ public class CharsetMapping {
Map<String, Integer> charsetNameToCollationPriorityMap = new TreeMap<String, Integer>();
Set<Integer> tempUTF8MB4Indexes = new HashSet<Integer>();
+ Collation notUsedCollation = new Collation(0, COLLATION_NOT_DEFINED, 0, NOT_USED);
for (int i = 1; i < MAP_SIZE; i++) {
- COLLATION_INDEX_TO_COLLATION_NAME[i] = collation[i].collationName;
- COLLATION_INDEX_TO_CHARSET[i] = collation[i].mysqlCharset;
- String charsetName = collation[i].mysqlCharset.charsetName;
+ Collation coll = collation[i] != null ? collation[i] : notUsedCollation;
+ COLLATION_INDEX_TO_COLLATION_NAME[i] = coll.collationName;
+ COLLATION_INDEX_TO_CHARSET[i] = coll.mysqlCharset;
+ String charsetName = coll.mysqlCharset.charsetName;
- if (!charsetNameToCollationIndexMap.containsKey(charsetName) || charsetNameToCollationPriorityMap.get(charsetName) < collation[i].priority) {
+ if (!charsetNameToCollationIndexMap.containsKey(charsetName) || charsetNameToCollationPriorityMap.get(charsetName) < coll.priority) {
charsetNameToCollationIndexMap.put(charsetName, i);
- charsetNameToCollationPriorityMap.put(charsetName, collation[i].priority);
+ charsetNameToCollationPriorityMap.put(charsetName, coll.priority);
}
// Filling indexes of utf8mb4 collations
@@ -539,16 +579,6 @@ public class CharsetMapping {
}
}
- // Sanity check
- for (int i = 1; i < MAP_SIZE; i++) {
- if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) {
- throw new RuntimeException("Assertion failure: No mapping from charset index " + i + " to a mysql collation");
- }
- if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) {
- throw new RuntimeException("Assertion failure: No mapping from charset index " + i + " to a Java character set");
- }
- }
-
CHARSET_NAME_TO_COLLATION_INDEX = Collections.unmodifiableMap(charsetNameToCollationIndexMap);
UTF8MB4_INDEXES = Collections.unmodifiableSet(tempUTF8MB4Indexes);
@@ -581,6 +611,8 @@ public class CharsetMapping {
tempMap.put("swedish", "latin1");
tempMap.put("ukrainian", "koi8u");
ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET = Collections.unmodifiableMap(tempMap);
+
+ collation = null;
}
public final static String getMysqlCharsetForJavaEncoding(String javaEncoding, Connection conn) throws SQLException {
@@ -603,7 +635,8 @@ public class CharsetMapping {
}
if (versionedProp == null || versionedProp.major < charset.major || versionedProp.minor < charset.minor
- || versionedProp.subminor < charset.subminor || versionedProp.priority < charset.priority) {
+ || versionedProp.subminor < charset.subminor || (versionedProp.priority < charset.priority && versionedProp.major == charset.major
+ && versionedProp.minor == charset.minor && versionedProp.subminor == charset.subminor)) {
if (charset.isOkayForVersion(conn)) {
versionedProp = charset;
}
diff --git a/src/com/mysql/jdbc/ConnectionImpl.java b/src/com/mysql/jdbc/ConnectionImpl.java
index 9debec4..4cfb89d 100644
--- a/src/com/mysql/jdbc/ConnectionImpl.java
+++ b/src/com/mysql/jdbc/ConnectionImpl.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -25,6 +25,7 @@ package com.mysql.jdbc;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
@@ -56,7 +57,6 @@ import java.util.Random;
import java.util.Stack;
import java.util.TimeZone;
import java.util.Timer;
-import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
@@ -267,16 +267,6 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
protected static Map<?, ?> roundRobinStatsMap;
/**
- * Actual collation index to collation name map for given server URLs.
- */
- private static final Map<String, Map<Number, String>> dynamicIndexToCollationMapByUrl = new HashMap<String, Map<Number, String>>();
-
- /**
- * Actual collation index to mysql charset name map for given server URLs.
- */
- private static final Map<String, Map<Integer, String>> dynamicIndexToCharsetMapByUrl = new HashMap<String, Map<Integer, String>>();
-
- /**
* Actual collation index to mysql charset name map of user defined charsets for given server URLs.
*/
private static final Map<String, Map<Integer, String>> customIndexToCharsetMapByUrl = new HashMap<String, Map<Integer, String>>();
@@ -492,15 +482,9 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
/** 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<Integer, String> indexToMysqlCharset = new HashMap<Integer, String>();
-
- public Map<Integer, String> indexToCustomMysqlCharset = null; //new HashMap<Integer, String>();
+ public Map<Integer, String> indexToCustomMysqlCharset = null;
- private Map<String, Integer> mysqlCharsetToCustomMblen = null; //new HashMap<String, Integer>();
+ private Map<String, Integer> mysqlCharsetToCustomMblen = null;
/** The I/O abstraction interface (network conn to MySQL server */
private transient MysqlIO io = null;
@@ -924,57 +908,32 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
*/
private void buildCollationMapping() throws SQLException {
- Map<Integer, String> indexToCharset = null;
- Map<Number, String> sortedCollationMap = null;
Map<Integer, String> customCharset = null;
Map<String, Integer> customMblen = null;
if (getCacheServerConfiguration()) {
- synchronized (dynamicIndexToCharsetMapByUrl) {
- indexToCharset = dynamicIndexToCharsetMapByUrl.get(getURL());
- sortedCollationMap = dynamicIndexToCollationMapByUrl.get(getURL());
+ synchronized (customIndexToCharsetMapByUrl) {
customCharset = customIndexToCharsetMapByUrl.get(getURL());
customMblen = customCharsetToMblenMapByUrl.get(getURL());
}
}
- if (indexToCharset == null) {
- indexToCharset = new HashMap<Integer, String>();
+ if (customCharset == null && getDetectCustomCollations() && versionMeetsMinimum(4, 1, 0)) {
- if (versionMeetsMinimum(4, 1, 0) && getDetectCustomCollations()) {
-
- java.sql.Statement stmt = null;
- java.sql.ResultSet results = null;
-
- try {
- sortedCollationMap = new TreeMap<Number, String>();
- customCharset = new HashMap<Integer, String>();
- customMblen = new HashMap<String, Integer>();
-
- 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;
- }
- }
+ java.sql.Statement stmt = null;
+ java.sql.ResultSet results = null;
- for (Iterator<Map.Entry<Number, String>> indexIter = sortedCollationMap.entrySet().iterator(); indexIter.hasNext();) {
- Map.Entry<Number, String> indexEntry = indexIter.next();
+ try {
+ customCharset = new HashMap<Integer, String>();
+ customMblen = new HashMap<String, Integer>();
- int collationIndex = indexEntry.getKey().intValue();
- String charsetName = indexEntry.getValue();
+ stmt = getMetadataSafeStatement();
- indexToCharset.put(collationIndex, charsetName);
+ try {
+ results = stmt.executeQuery("SHOW COLLATION");
+ while (results.next()) {
+ int collationIndex = ((Number) results.getObject(3)).intValue();
+ String charsetName = results.getString(2);
// 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
@@ -987,70 +946,61 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
customMblen.put(charsetName, null);
}
}
+ } catch (SQLException ex) {
+ if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
+ throw ex;
+ }
+ }
- // 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 there is a number of custom charsets we should execute SHOW CHARACTER SET to know their 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"));
}
}
- }
-
- if (getCacheServerConfiguration()) {
- synchronized (dynamicIndexToCharsetMapByUrl) {
- dynamicIndexToCharsetMapByUrl.put(getURL(), indexToCharset);
- dynamicIndexToCollationMapByUrl.put(getURL(), sortedCollationMap);
- customIndexToCharsetMapByUrl.put(getURL(), customCharset);
- customCharsetToMblenMapByUrl.put(getURL(), customMblen);
+ } catch (SQLException ex) {
+ if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
+ throw ex;
}
}
+ }
- } 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 (getCacheServerConfiguration()) {
+ synchronized (customIndexToCharsetMapByUrl) {
+ customIndexToCharsetMapByUrl.put(getURL(), customCharset);
+ customCharsetToMblenMapByUrl.put(getURL(), customMblen);
}
+ }
- if (stmt != null) {
- try {
- stmt.close();
- } catch (java.sql.SQLException sqlE) {
- // ignore
- }
+ } 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
}
}
- } else {
- for (int i = 1; i < CharsetMapping.MAP_SIZE; i++) {
- indexToCharset.put(i, CharsetMapping.getMysqlCharsetNameForCollationIndex(i));
- }
- if (getCacheServerConfiguration()) {
- synchronized (dynamicIndexToCharsetMapByUrl) {
- dynamicIndexToCharsetMapByUrl.put(getURL(), indexToCharset);
+
+ if (stmt != null) {
+ try {
+ stmt.close();
+ } catch (java.sql.SQLException sqlE) {
+ // ignore
}
}
}
-
}
- this.indexToMysqlCharset = Collections.unmodifiableMap(indexToCharset);
if (customCharset != null) {
this.indexToCustomMysqlCharset = Collections.unmodifiableMap(customCharset);
}
@@ -1156,6 +1106,8 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
canHandleAsStatement = false;
} else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "SHOW WARNINGS") && versionMeetsMinimum(5, 7, 2)) {
canHandleAsStatement = false;
+ } else if (sql.startsWith(StatementImpl.PING_MARKER)) {
+ canHandleAsStatement = false;
}
return canHandleAsStatement;
@@ -2776,8 +2728,13 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
if (charsetIndex != MysqlDefs.NO_CHARSET_INFO) {
try {
- if (this.indexToMysqlCharset.size() > 0) {
- javaEncoding = CharsetMapping.getJavaEncodingForMysqlCharset(this.indexToMysqlCharset.get(charsetIndex), getEncoding());
+ // getting charset name from dynamic maps in connection; we do it before checking against static maps because custom charset on server can be mapped
+ // to index from our static map key's diapason
+ if (this.indexToCustomMysqlCharset != null) {
+ String cs = this.indexToCustomMysqlCharset.get(charsetIndex);
+ if (cs != null) {
+ javaEncoding = CharsetMapping.getJavaEncodingForMysqlCharset(cs, getEncoding());
+ }
}
// checking against static maps if no custom charset found
if (javaEncoding == null) {
@@ -3352,8 +3309,6 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
}
}
- boolean overrideDefaultAutocommit = isAutoCommitNonDefaultOnServer();
-
configureClientCharacterSet(false);
try {
@@ -3368,16 +3323,7 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
if (versionMeetsMinimum(3, 23, 15)) {
this.transactionsSupported = true;
-
- if (!overrideDefaultAutocommit) {
- try {
- setAutoCommit(true); // to override anything the server is set to...reqd by JDBC spec.
- } catch (SQLException ex) {
- if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
- throw ex;
- }
- }
- }
+ handleAutoCommitDefaults();
} else {
this.transactionsSupported = false;
}
@@ -3459,36 +3405,26 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
}
/**
- * Has the default autocommit value of 0 been changed on the server
- * via init_connect?
- *
- * @return true if autocommit is not the default of '0' on the server.
- *
- * @throws SQLException
+ * Resets a default auto-commit value of 0 to 1, as required by JDBC specification.
+ * Takes into account that the default auto-commit value of 0 may have been changed on the server via init_connect.
*/
- private boolean isAutoCommitNonDefaultOnServer() throws SQLException {
- boolean overrideDefaultAutocommit = false;
+ private void handleAutoCommitDefaults() throws SQLException {
+ boolean resetAutoCommitDefault = false;
- String initConnectValue = this.serverVariables.get("init_connect");
-
- if (versionMeetsMinimum(4, 1, 2) && initConnectValue != null && initConnectValue.length() > 0) {
- if (!getElideSetAutoCommits()) {
+ if (!getElideSetAutoCommits()) {
+ String initConnectValue = this.serverVariables.get("init_connect");
+ if (versionMeetsMinimum(4, 1, 2) && initConnectValue != null && initConnectValue.length() > 0) {
// auto-commit might have changed
java.sql.ResultSet rs = null;
java.sql.Statement stmt = null;
try {
stmt = getMetadataSafeStatement();
-
rs = stmt.executeQuery("SELECT @@session.autocommit");
-
if (rs.next()) {
this.autoCommit = rs.getBoolean(1);
- if (this.autoCommit != true) {
- overrideDefaultAutocommit = true;
- }
+ resetAutoCommitDefault = !this.autoCommit;
}
-
} finally {
if (rs != null) {
try {
@@ -3497,7 +3433,6 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
// do nothing
}
}
-
if (stmt != null) {
try {
stmt.close();
@@ -3507,15 +3442,24 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
}
}
} else {
- if (this.getIO().isSetNeededForAutoCommitMode(true)) {
- // we're not in standard autocommit=true mode
- this.autoCommit = false;
- overrideDefaultAutocommit = true;
- }
+ // reset it anyway, the server may have been initialized with --autocommit=0
+ resetAutoCommitDefault = true;
}
+ } else if (this.getIO().isSetNeededForAutoCommitMode(true)) {
+ // we're not in standard autocommit=true mode
+ this.autoCommit = false;
+ resetAutoCommitDefault = true;
}
- return overrideDefaultAutocommit;
+ if (resetAutoCommitDefault) {
+ try {
+ setAutoCommit(true); // required by JDBC spec
+ } catch (SQLException ex) {
+ if (ex.getErrorCode() != MysqlErrorNumbers.ER_MUST_CHANGE_PASSWORD || getDisconnectOnExpiredPasswords()) {
+ throw ex;
+ }
+ }
+ }
}
public boolean isClientTzUTC() {
@@ -4778,7 +4722,7 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
* If a connection is in auto-commit mode, than all its SQL statements will
* be executed and committed as individual transactions. Otherwise, its SQL
* statements are grouped into transactions that are terminated by either
- * commit() or rollback(). By default, new connections are in auto- commit
+ * commit() or rollback(). By default, new connections are in auto-commit
* mode. The commit occurs when the statement completes or the next execute
* occurs, whichever comes first. In the case of statements returning a
* ResultSet, the statement completes when the last row of the ResultSet has
@@ -4786,12 +4730,8 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
* single statement may return multiple results as well as output parameter
* values. Here the commit occurs when all results and output param values
* have been retrieved.
- * <p>
- * <b>Note:</b> MySQL does not support transactions, so this method is a no-op.
- * </p>
*
* @param autoCommitFlag
- * -
* true enables auto-commit; false disables it
* @exception SQLException
* if a database access error occurs
@@ -5519,19 +5459,7 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
}
checkClosed();
- final MysqlIO mysqlIo = this.io;
-
- executor.execute(new Runnable() {
-
- public void run() {
- try {
- setSocketTimeout(milliseconds); // for re-connects
- mysqlIo.setSocketTimeout(milliseconds);
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }
- });
+ executor.execute(new NetworkTimeoutSetter(this, this.io, milliseconds));
}
}
@@ -5550,4 +5478,33 @@ public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLCon
public void setProfilerEventHandlerInstance(ProfilerEventHandler h) {
this.eventSink = h;
}
+
+ private static class NetworkTimeoutSetter implements Runnable {
+ private final WeakReference<ConnectionImpl> connImplRef;
+ private final WeakReference<MysqlIO> mysqlIoRef;
+ private final int milliseconds;
+
+ public NetworkTimeoutSetter(ConnectionImpl conn, MysqlIO io, int milliseconds) {
+ this.connImplRef = new WeakReference<ConnectionImpl>(conn);
+ this.mysqlIoRef = new WeakReference<MysqlIO>(io);
+ this.milliseconds = milliseconds;
+ }
+
+ public void run() {
+ try {
+ ConnectionImpl conn = this.connImplRef.get();
+ if (conn != null) {
+ synchronized (conn.getConnectionMutex()) {
+ conn.setSocketTimeout(this.milliseconds); // for re-connects
+ MysqlIO io = this.mysqlIoRef.get();
+ if (io != null) {
+ io.setSocketTimeout(this.milliseconds);
+ }
+ }
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
}
diff --git a/src/com/mysql/jdbc/ConnectionPropertiesImpl.java b/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
index ae8ea44..50c67d7 100644
--- a/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
+++ b/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -1767,7 +1767,10 @@ public class ConnectionPropertiesImpl implements Serializable, ConnectionPropert
* @see com.mysql.jdbc.IConnectionProperties#getElideSetAutoCommits()
*/
public boolean getElideSetAutoCommits() {
- return this.elideSetAutoCommits.getValueAsBoolean();
+ // Server Bug#66884 (SERVER_STATUS is always initiated with SERVER_STATUS_AUTOCOMMIT=1) invalidates this feature.
+ return false;
+ // TODO Turn this feature back on as soon as the server bug is fixed. Consider making it version specific.
+ // return this.elideSetAutoCommits.getValueAsBoolean();
}
/*
diff --git a/src/com/mysql/jdbc/Field.java b/src/com/mysql/jdbc/Field.java
index 21aeb50..98201aa 100644
--- a/src/com/mysql/jdbc/Field.java
+++ b/src/com/mysql/jdbc/Field.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -608,6 +608,10 @@ public class Field {
return null;
}
+ if (stringLength == 0) {
+ return "";
+ }
+
String stringVal = null;
if (this.connection != null) {
diff --git a/src/com/mysql/jdbc/MysqlDefs.java b/src/com/mysql/jdbc/MysqlDefs.java
index 9ae7897..34ed20c 100644
--- a/src/com/mysql/jdbc/MysqlDefs.java
+++ b/src/com/mysql/jdbc/MysqlDefs.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -60,15 +60,15 @@ public final class MysqlDefs {
static final int CONNECT = 11;
- static final int CREATE_DB = 5;
+ static final int CREATE_DB = 5; // Not used; deprecated?
static final int DEBUG = 13;
static final int DELAYED_INSERT = 16;
- static final int DROP_DB = 6;
+ static final int DROP_DB = 6; // Not used; deprecated?
- static final int FIELD_LIST = 4;
+ static final int FIELD_LIST = 4; // Not used; deprecated in MySQL 5.7.11 and MySQL 8.0.0.
static final int FIELD_TYPE_BIT = 16;
@@ -151,15 +151,15 @@ public final class MysqlDefs {
static final int PING = 14;
- static final int PROCESS_INFO = 10;
+ static final int PROCESS_INFO = 10; // Not used; deprecated in MySQL 5.7.11 and MySQL 8.0.0.
- static final int PROCESS_KILL = 12;
+ static final int PROCESS_KILL = 12; // Not used; deprecated in MySQL 5.7.11 and MySQL 8.0.0.
static final int QUERY = 3;
static final int QUIT = 1;
- static final int RELOAD = 7;
+ static final int RELOAD = 7; // Not used; deprecated in MySQL 5.7.11 and MySQL 8.0.0.
static final int SHUTDOWN = 8;
diff --git a/src/com/mysql/jdbc/MysqlIO.java b/src/com/mysql/jdbc/MysqlIO.java
index 7878863..1457d9c 100644
--- a/src/com/mysql/jdbc/MysqlIO.java
+++ b/src/com/mysql/jdbc/MysqlIO.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -1720,6 +1720,13 @@ public class MysqlIO {
}
if (challenge.isOKPacket()) {
+ // get the server status from the challenge packet.
+ challenge.newReadLength(); // affected_rows
+ challenge.newReadLength(); // last_insert_id
+
+ this.oldServerStatus = this.serverStatus;
+ this.serverStatus = challenge.readInt();
+
// if OK packet then finish handshake
plugin.destroy();
break;
@@ -2486,17 +2493,13 @@ public class MysqlIO {
this.sendPacket.writeByte((byte) command);
- if ((command == MysqlDefs.INIT_DB) || (command == MysqlDefs.CREATE_DB) || (command == MysqlDefs.DROP_DB) || (command == MysqlDefs.QUERY)
- || (command == MysqlDefs.COM_PREPARE)) {
+ if ((command == MysqlDefs.INIT_DB) || (command == MysqlDefs.QUERY) || (command == MysqlDefs.COM_PREPARE)) {
if (extraDataCharEncoding == null) {
this.sendPacket.writeStringNoNull(extraData);
} else {
this.sendPacket.writeStringNoNull(extraData, extraDataCharEncoding, this.connection.getServerCharset(),
this.connection.parserKnowsUnicode(), this.connection);
}
- } else if (command == MysqlDefs.PROCESS_KILL) {
- long id = Long.parseLong(extraData);
- this.sendPacket.writeLong(id);
}
send(this.sendPacket, this.sendPacket.getPosition());
@@ -4977,7 +4980,9 @@ public class MysqlIO {
protected void setSocketTimeout(int milliseconds) throws SQLException {
try {
- this.mysqlConnection.setSoTimeout(milliseconds);
+ if (this.mysqlConnection != null) {
+ this.mysqlConnection.setSoTimeout(milliseconds);
+ }
} catch (SocketException e) {
SQLException sqlEx = SQLError.createSQLException("Invalid socket timeout value or state", SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
getExceptionInterceptor());
diff --git a/src/com/mysql/jdbc/NonRegisteringDriver.java b/src/com/mysql/jdbc/NonRegisteringDriver.java
index 625325d..8b68e84 100644
--- a/src/com/mysql/jdbc/NonRegisteringDriver.java
+++ b/src/com/mysql/jdbc/NonRegisteringDriver.java
@@ -101,9 +101,11 @@ public class NonRegisteringDriver implements java.sql.Driver {
}
static {
- AbandonedConnectionCleanupThread referenceThread = new AbandonedConnectionCleanupThread();
- referenceThread.setDaemon(true);
- referenceThread.start();
+ try {
+ Class.forName(AbandonedConnectionCleanupThread.class.getName());
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
}
/**
diff --git a/src/com/mysql/jdbc/PreparedStatement.java b/src/com/mysql/jdbc/PreparedStatement.java
index 1de22fa..0d1596b 100644
--- a/src/com/mysql/jdbc/PreparedStatement.java
+++ b/src/com/mysql/jdbc/PreparedStatement.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -822,11 +822,7 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
detectFractionalSecondsSupport();
this.originalSql = sql;
- if (this.originalSql.startsWith(PING_MARKER)) {
- this.doPingInstead = true;
- } else {
- this.doPingInstead = false;
- }
+ this.doPingInstead = this.originalSql.startsWith(PING_MARKER);
this.dbmd = this.connection.getMetaData();
@@ -1134,26 +1130,34 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
MySQLConnection locallyScopedConn = this.connection;
- if (!checkReadOnlySafeStatement()) {
+ if (!this.doPingInstead && !checkReadOnlySafeStatement()) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.20") + Messages.getString("PreparedStatement.21"),
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
ResultSetInternalMethods rs = null;
- CachedResultSetMetaData cachedMetadata = null;
-
this.lastQueryIsOnDupKeyUpdate = false;
if (this.retrieveGeneratedKeys) {
this.lastQueryIsOnDupKeyUpdate = containsOnDuplicateKeyUpdateInSQL();
}
+ this.batchedGeneratedKeys = null;
+
+ resetCancelledState();
+
+ implicitlyCloseAllOpenResults();
+
clearWarnings();
- setupStreamingTimeout(locallyScopedConn);
+ if (this.doPingInstead) {
+ doPingInstead();
- this.batchedGeneratedKeys = null;
+ return true;
+ }
+
+ setupStreamingTimeout(locallyScopedConn);
Buffer sendPacket = fillSendPacket();
@@ -1167,6 +1171,7 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
//
// Check if we have cached metadata for this query...
//
+ CachedResultSetMetaData cachedMetadata = null;
if (locallyScopedConn.getCacheResultSetMetadata()) {
cachedMetadata = locallyScopedConn.getCachedMetaData(this.originalSql);
}
@@ -1507,7 +1512,7 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
try {
try {
batchedStatement = /* FIXME -if we ever care about folks proxying our MySQLConnection */
- prepareBatchedInsertSQL(locallyScopedConn, numValuesPerBatch);
+ prepareBatchedInsertSQL(locallyScopedConn, numValuesPerBatch);
if (locallyScopedConn.getEnableQueryTimeouts() && batchTimeout != 0 && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
timeoutTask = new CancelTask(batchedStatement);
@@ -1832,18 +1837,10 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
synchronized (checkClosed().getConnectionMutex()) {
try {
- resetCancelledState();
-
MySQLConnection locallyScopedConnection = this.connection;
this.numberOfExecutions++;
- if (this.doPingInstead) {
- doPingInstead();
-
- return this.results;
- }
-
ResultSetInternalMethods rs;
CancelTask timeoutTask = null;
@@ -1925,18 +1922,24 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
checkForDml(this.originalSql, this.firstCharOfStmt);
- CachedResultSetMetaData cachedMetadata = null;
+ this.batchedGeneratedKeys = null;
+
+ resetCancelledState();
+
+ implicitlyCloseAllOpenResults();
clearWarnings();
- this.batchedGeneratedKeys = null;
+ if (this.doPingInstead) {
+ doPingInstead();
+
+ return this.results;
+ }
setupStreamingTimeout(locallyScopedConn);
Buffer sendPacket = fillSendPacket();
- implicitlyCloseAllOpenResults();
-
String oldCatalog = null;
if (!locallyScopedConn.getCatalog().equals(this.currentCatalog)) {
@@ -1947,6 +1950,7 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
//
// Check if we have cached metadata for this query...
//
+ CachedResultSetMetaData cachedMetadata = null;
if (locallyScopedConn.getCacheResultSetMetadata()) {
cachedMetadata = locallyScopedConn.getCachedMetaData(this.originalSql);
}
@@ -2045,6 +2049,8 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
throw SQLError.createSQLException(Messages.getString("PreparedStatement.37"), "01S03", getExceptionInterceptor());
}
+ resetCancelledState();
+
implicitlyCloseAllOpenResults();
ResultSetInternalMethods rs = null;
@@ -2589,8 +2595,8 @@ public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements j
return ((c == 'y') && (n == 2)) ? 'X'
: (((c == 'y') && (n < 4)) ? 'y' : ((c == 'y') ? 'M' : (((c == 'M') && (n == 2)) ? 'Y'
: (((c == 'M') && (n < 3)) ? 'M' : ((c == 'M') ? 'd' : (((c == 'd') && (n < 2)) ? 'd' : ((c == 'd') ? 'H' : (((c == 'H') && (n < 2))
- ? 'H'
- : ((c == 'H') ? 'm' : (((c == 'm') && (n < 2)) ? 'm' : ((c == 'm') ? 's' : (((c == 's') && (n < 2)) ? 's' : 'W'))))))))))));
+ ? 'H' : ((c == 'H') ? 'm'
+ : (((c == 'm') && (n < 2)) ? 'm' : ((c == 'm') ? 's' : (((c == 's') && (n < 2)) ? 's' : 'W'))))))))))));
}
/**
diff --git a/src/com/mysql/jdbc/ResultSetImpl.java b/src/com/mysql/jdbc/ResultSetImpl.java
index d6cda59..44a6e2c 100644
--- a/src/com/mysql/jdbc/ResultSetImpl.java
+++ b/src/com/mysql/jdbc/ResultSetImpl.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -3429,24 +3429,26 @@ public class ResultSetImpl implements ResultSetInternalMethods {
byte[] data = getBytes(columnIndex);
Object obj = data;
- if ((data != null) && (data.length >= 2)) {
- if ((data[0] == -84) && (data[1] == -19)) {
- // Serialized object?
- try {
- ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
- ObjectInputStream objIn = new ObjectInputStream(bytesIn);
- obj = objIn.readObject();
- objIn.close();
- bytesIn.close();
- } catch (ClassNotFoundException cnfe) {
- throw SQLError.createSQLException(Messages.getString("ResultSet.Class_not_found___91") + cnfe.toString()
- + Messages.getString("ResultSet._while_reading_serialized_object_92"), getExceptionInterceptor());
- } catch (IOException ex) {
- obj = data; // not serialized?
+ if (this.connection.getAutoDeserialize()) {
+ if ((data != null) && (data.length >= 2)) {
+ if ((data[0] == -84) && (data[1] == -19)) {
+ // Serialized object?
+ try {
+ ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
+ ObjectInputStream objIn = new ObjectInputStream(bytesIn);
+ obj = objIn.readObject();
+ objIn.close();
+ bytesIn.close();
+ } catch (ClassNotFoundException cnfe) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.Class_not_found___91") + cnfe.toString()
+ + Messages.getString("ResultSet._while_reading_serialized_object_92"), getExceptionInterceptor());
+ } catch (IOException ex) {
+ obj = data; // not serialized?
+ }
}
- }
- return obj.toString();
+ return obj.toString();
+ }
}
return extractStringFromNativeColumn(columnIndex, mysqlType);
diff --git a/src/com/mysql/jdbc/SQLError.java b/src/com/mysql/jdbc/SQLError.java
index ab20469..b598744 100644
--- a/src/com/mysql/jdbc/SQLError.java
+++ b/src/com/mysql/jdbc/SQLError.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -55,7 +55,7 @@ public class SQLError {
// SQL-92
public static final String SQL_STATE_WARNING = "01000";
public static final String SQL_STATE_DISCONNECT_ERROR = "01002";
- public static final String SQL_STATE_DATE_TRUNCATED = "01004";
+ public static final String SQL_STATE_DATA_TRUNCATED = "01004";
public static final String SQL_STATE_PRIVILEGE_NOT_REVOKED = "01006";
public static final String SQL_STATE_NO_DATA = "02000";
public static final String SQL_STATE_WRONG_NO_OF_PARAMETERS = "07001";
@@ -160,7 +160,7 @@ public class SQLError {
sqlStateMessages = new HashMap<String, String>();
sqlStateMessages.put(SQL_STATE_DISCONNECT_ERROR, Messages.getString("SQLError.35"));
- sqlStateMessages.put(SQL_STATE_DATE_TRUNCATED, Messages.getString("SQLError.36"));
+ sqlStateMessages.put(SQL_STATE_DATA_TRUNCATED, Messages.getString("SQLError.36"));
sqlStateMessages.put(SQL_STATE_PRIVILEGE_NOT_REVOKED, Messages.getString("SQLError.37"));
sqlStateMessages.put(SQL_STATE_INVALID_CONNECTION_ATTRIBUTE, Messages.getString("SQLError.38"));
sqlStateMessages.put(SQL_STATE_ERROR_IN_ROW, Messages.getString("SQLError.39"));
diff --git a/src/com/mysql/jdbc/StatementImpl.java b/src/com/mysql/jdbc/StatementImpl.java
index ed9fe32..411b82a 100644
--- a/src/com/mysql/jdbc/StatementImpl.java
+++ b/src/com/mysql/jdbc/StatementImpl.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -749,6 +749,16 @@ public class StatementImpl implements Statement {
resetCancelledState();
+ implicitlyCloseAllOpenResults();
+
+ if (sql.charAt(0) == '/') {
+ if (sql.startsWith(PING_MARKER)) {
+ doPingInstead();
+
+ return true;
+ }
+ }
+
char firstNonWsChar = StringUtils.firstAlphaCharUc(sql, findStartOfStatement(sql));
boolean maybeSelect = firstNonWsChar == 'S';
@@ -781,16 +791,6 @@ public class StatementImpl implements Statement {
}
}
- implicitlyCloseAllOpenResults();
-
- if (sql.charAt(0) == '/') {
- if (sql.startsWith(PING_MARKER)) {
- doPingInstead();
-
- return true;
- }
- }
-
CachedResultSetMetaData cachedMetaData = null;
ResultSetInternalMethods rs = null;
@@ -1295,9 +1295,19 @@ public class StatementImpl implements Statement {
this.retrieveGeneratedKeys = false;
+ checkNullOrEmptyQuery(sql);
+
resetCancelledState();
- checkNullOrEmptyQuery(sql);
+ implicitlyCloseAllOpenResults();
+
+ if (sql.charAt(0) == '/') {
+ if (sql.startsWith(PING_MARKER)) {
+ doPingInstead();
+
+ return this.results;
+ }
+ }
setupStreamingTimeout(locallyScopedConn);
@@ -1313,18 +1323,8 @@ public class StatementImpl implements Statement {
char firstStatementChar = StringUtils.firstAlphaCharUc(sql, findStartOfStatement(sql));
- if (sql.charAt(0) == '/') {
- if (sql.startsWith(PING_MARKER)) {
- doPingInstead();
-
- return this.results;
- }
- }
-
checkForDml(sql, firstStatementChar);
- implicitlyCloseAllOpenResults();
-
CachedResultSetMetaData cachedMetaData = null;
if (useServerFetch()) {
diff --git a/src/com/mysql/jdbc/Util.java b/src/com/mysql/jdbc/Util.java
index b1e4bfe..ba4bf17 100644
--- a/src/com/mysql/jdbc/Util.java
+++ b/src/com/mysql/jdbc/Util.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -583,7 +583,7 @@ public class Util {
if (clazz.isInterface()) {
try {
- if (isJdbcPackage(clazz.getPackage().getName())) {
+ if (isJdbcPackage(Util.getPackageName(clazz))) {
Util.isJdbcInterfaceCache.putIfAbsent(clazz, true);
return true;
}
@@ -615,8 +615,8 @@ public class Util {
private static final String MYSQL_JDBC_PACKAGE_ROOT;
static {
- String packageName = MultiHostConnectionProxy.class.getPackage().getName();
- // assume that packageName includes "jdbc"
+ String packageName = Util.getPackageName(MultiHostConnectionProxy.class);
+ // assume that packageName contains "jdbc"
MYSQL_JDBC_PACKAGE_ROOT = packageName.substring(0, packageName.indexOf("jdbc") + 4);
}
@@ -699,4 +699,21 @@ public class Util {
}
return intArray;
}
+
+ /**
+ * Returns the package name of the given class.
+ * Using clazz.getPackage().getName() is not an alternative because under some class loaders the method getPackage() just returns null.
+ *
+ * @param clazz
+ * the Class from which to get the package name
+ * @return the package name
+ */
+ public static String getPackageName(Class<?> clazz) {
+ String fqcn = clazz.getName();
+ int classNameStartsAt = fqcn.lastIndexOf('.');
+ if (classNameStartsAt > 0) {
+ return fqcn.substring(0, classNameStartsAt);
+ }
+ return "";
+ }
}
\ No newline at end of file
diff --git a/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java b/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java
index 972be67..40a2197 100644
--- a/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java
+++ b/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -32,6 +32,7 @@ import java.util.Map;
import com.mysql.jdbc.ExceptionInterceptor;
import com.mysql.jdbc.SQLError;
+import com.mysql.jdbc.Util;
/**
* Base class for all wrapped instances created by LogicalHandle
@@ -104,7 +105,7 @@ abstract class WrapperBase {
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> iclass : interfaces) {
- String packageName = iclass.getPackage().getName();
+ String packageName = Util.getPackageName(iclass);
if ("java.sql".equals(packageName) || "javax.sql".equals(packageName)) {
return Proxy.newProxyInstance(toProxy.getClass().getClassLoader(), interfaces, new ConnectionErrorFiringInvocationHandler(toProxy));
diff --git a/src/com/mysql/jdbc/log/LogFactory.java b/src/com/mysql/jdbc/log/LogFactory.java
index f89e805..7f7e421 100644
--- a/src/com/mysql/jdbc/log/LogFactory.java
+++ b/src/com/mysql/jdbc/log/LogFactory.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -29,6 +29,7 @@ import java.sql.SQLException;
import com.mysql.jdbc.ExceptionInterceptor;
import com.mysql.jdbc.SQLError;
+import com.mysql.jdbc.Util;
/**
* Creates instances of loggers for the driver to use.
@@ -63,7 +64,7 @@ public class LogFactory {
try {
loggerClass = Class.forName(className);
} catch (ClassNotFoundException nfe) {
- loggerClass = Class.forName(Log.class.getPackage().getName() + "." + className);
+ loggerClass = Class.forName(Util.getPackageName(Log.class) + "." + className);
}
Constructor<?> constructor = loggerClass.getConstructor(new Class[] { String.class });
diff --git a/src/testsuite/BaseTestCase.java b/src/testsuite/BaseTestCase.java
index 2f50007..7da1d03 100644
--- a/src/testsuite/BaseTestCase.java
+++ b/src/testsuite/BaseTestCase.java
@@ -923,36 +923,36 @@ public abstract class BaseTestCase extends TestCase {
}
protected static <EX extends Throwable> EX assertThrows(Class<EX> throwable, Callable<?> testRoutine) {
- try {
- testRoutine.call();
- } catch (Throwable t) {
- if (!throwable.isAssignableFrom(t.getClass())) {
- fail("Expected exception of type '" + throwable.getName() + "' but instead a exception of type '" + t.getClass().getName() + "' was thrown.");
- }
-
- return throwable.cast(t);
- }
- fail("Expected exception of type '" + throwable.getName() + "'.");
+ return assertThrows("", throwable, null, testRoutine);
+ }
- // never reaches here
- return null;
+ protected static <EX extends Throwable> EX assertThrows(String message, Class<EX> throwable, Callable<?> testRoutine) {
+ return assertThrows(message, throwable, null, testRoutine);
}
protected static <EX extends Throwable> EX assertThrows(Class<EX> throwable, String msgMatchesRegex, Callable<?> testRoutine) {
+ return assertThrows("", throwable, msgMatchesRegex, testRoutine);
+ }
+
+ protected static <EX extends Throwable> EX assertThrows(String message, Class<EX> throwable, String msgMatchesRegex, Callable<?> testRoutine) {
+ if (message.length() > 0) {
+ message += " ";
+ }
try {
testRoutine.call();
} catch (Throwable t) {
if (!throwable.isAssignableFrom(t.getClass())) {
- fail("Expected exception of type '" + throwable.getName() + "' but instead a exception of type '" + t.getClass().getName() + "' was thrown.");
+ fail(message + "expected exception of type '" + throwable.getName() + "' but instead a exception of type '" + t.getClass().getName()
+ + "' was thrown.");
}
- if (!t.getMessage().matches(msgMatchesRegex)) {
- fail("The error message «" + t.getMessage() + "» was expected to match «" + msgMatchesRegex + "».");
+ if (msgMatchesRegex != null && !t.getMessage().matches(msgMatchesRegex)) {
+ fail(message + "the error message «" + t.getMessage() + "» was expected to match «" + msgMatchesRegex + "».");
}
return throwable.cast(t);
}
- fail("Expected exception of type '" + throwable.getName() + "'.");
+ fail(message + "expected exception of type '" + throwable.getName() + "'.");
// never reaches here
return null;
diff --git a/src/testsuite/fabric/TestShardMapping.java b/src/testsuite/fabric/TestShardMapping.java
index 24a2675..f000b28 100644
--- a/src/testsuite/fabric/TestShardMapping.java
+++ b/src/testsuite/fabric/TestShardMapping.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -23,8 +23,16 @@
package testsuite.fabric;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
import com.mysql.fabric.HashShardMapping;
import com.mysql.fabric.RangeShardMapping;
@@ -120,4 +128,66 @@ public class TestShardMapping extends TestCase {
assertNotNull(mapping.getGroupNameForKey("" + i));
}
}
+
+ /**
+ * Tests fix for Bug#82203 - com.mysql.fabric.HashShardMapping is not thread safe.
+ *
+ * This test is non-deterministic but most runs used to fail before 5 to 10 seconds. This test runs at most for 30 seconds.
+ */
+ public void testBug82203() throws Throwable {
+ int numberOfThreads = 2;
+
+ ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
+ List<Future<?>> resultList = new ArrayList<Future<?>>();
+
+ for (int i = 0; i < numberOfThreads; i++) {
+ resultList.add(executorService.submit(new TestBug82203RunnableMock(30)));
+ }
+
+ for (Future<?> f : resultList) {
+ try {
+ f.get();
+ } catch (ExecutionException e) {
+ if (e.getCause() != null) {
+ throw e.getCause();
+ }
+ throw e;
+ }
+ }
+ executorService.shutdown();
+ }
+
+ private static class TestBug82203RunnableMock extends HashShardMapping implements Runnable {
+ private static volatile boolean run = true;
+ private long time;
+
+ public TestBug82203RunnableMock(int secs) {
+ super(0, null, null, null, Collections.singleton(new ShardIndex("", 1, "")));
+ this.time = TimeUnit.SECONDS.toMillis(secs);
+ }
+
+ public void run() {
+ try {
+ long now = System.currentTimeMillis();
+ while (run && System.currentTimeMillis() - now < this.time) {
+ int id = ((int) (Math.random() * 100)) % 100 + 1;
+ String key = makeKey(id);
+ getShardIndexForKey(key);
+ }
+ } catch (Exception e) {
+ fail("Due to: " + e);
+ } finally {
+ run = false;
+ }
+ }
+
+ private String makeKey(int len) {
+ char[] chars = new char[len];
+ for (int i = 0; i < len; i++) {
+ int r = ((int) (Math.random() * 100)) % 52;
+ chars[i] = (char) (r < 26 ? 'a' + r : 'A' + r - 26);
+ }
+ return String.valueOf(chars);
+ }
+ }
}
diff --git a/src/testsuite/regression/CharsetRegressionTest.java b/src/testsuite/regression/CharsetRegressionTest.java
index 9b55ef5..71f9c49 100644
--- a/src/testsuite/regression/CharsetRegressionTest.java
+++ b/src/testsuite/regression/CharsetRegressionTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -27,6 +27,7 @@ import java.sql.SQLException;
import java.util.Properties;
import java.util.concurrent.Callable;
+import com.mysql.jdbc.CharsetMapping;
import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.ResultSetInternalMethods;
@@ -118,4 +119,18 @@ public class CharsetRegressionTest extends BaseTestCase {
}
}
}
+
+ /**
+ * Tests fix for Bug#25504578, CONNECT FAILS WHEN CONNECTIONCOLLATION=ISO-8859-13
+ *
+ * @throws Exception
+ */
+ public void testBug25504578() throws Exception {
+
+ Properties p = new Properties();
+ String cjCharset = CharsetMapping.getJavaEncodingForMysqlCharset("latin7");
+ p.setProperty("characterEncoding", cjCharset);
+
+ getConnectionWithProps(p);
+ }
}
diff --git a/src/testsuite/regression/ConnectionRegressionTest.java b/src/testsuite/regression/ConnectionRegressionTest.java
index 4731056..15dae45 100644
--- a/src/testsuite/regression/ConnectionRegressionTest.java
+++ b/src/testsuite/regression/ConnectionRegressionTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -1065,15 +1065,14 @@ public class ConnectionRegressionTest extends BaseTestCase {
* if the test fails.
*/
public void testBug11976() throws Exception {
- if (!versionMeetsMinimum(6, 0)) {
- return; // server status is broken until MySQL-6.0
- }
-
Properties props = new Properties();
props.setProperty("useConfigs", "maxPerformance");
Connection maxPerfConn = getConnectionWithProps(props);
- assertEquals(true, ((com.mysql.jdbc.Connection) maxPerfConn).getElideSetAutoCommits());
+ // 'elideSetAutoCommits' feature was turned off due to Server Bug#66884. See also ConnectionPropertiesImpl#getElideSetAutoCommits().
+ assertEquals(false, ((com.mysql.jdbc.Connection) maxPerfConn).getElideSetAutoCommits());
+ // TODO Turn this test back on as soon as the server bug is fixed. Consider making it version specific.
+ // assertEquals(true, ((com.mysql.jdbc.Connection) maxPerfConn).getElideSetAutoCommits());
}
/**
@@ -1536,8 +1535,11 @@ public class ConnectionRegressionTest extends BaseTestCase {
* if the test fails.
*/
public void testBug24706() throws Exception {
- if (!versionMeetsMinimum(6, 0)) {
- return; // server status isn't there to support this feature
+ // 'elideSetAutoCommits' feature was turned off due to Server Bug#66884. See also ConnectionPropertiesImpl#getElideSetAutoCommits().
+ // TODO Turn this test back on as soon as the server bug is fixed. Consider making it version specific.
+ boolean ignoreTest = true;
+ if (ignoreTest) {
+ return;
}
Properties props = new Properties();
@@ -1577,7 +1579,6 @@ public class ConnectionRegressionTest extends BaseTestCase {
if (c != null) {
c.close();
}
-
}
}
@@ -9807,7 +9808,10 @@ public class ConnectionRegressionTest extends BaseTestCase {
Connection testConn = getConnectionWithProps(props);
assertEquals(testCase, useLocTransSt, ((ConnectionProperties) testConn).getUseLocalTransactionState());
- assertEquals(testCase, useElideSetAC, ((ConnectionProperties) testConn).getElideSetAutoCommits());
+ // 'elideSetAutoCommits' feature was turned off due to Server Bug#66884. See also ConnectionPropertiesImpl#getElideSetAutoCommits().
+ assertFalse(testCase, ((ConnectionProperties) testConn).getElideSetAutoCommits());
+ // TODO Turn this test back on as soon as the server bug is fixed. Consider making it version specific.
+ // assertEquals(testCase, useElideSetAC, ((ConnectionProperties) testConn).getElideSetAutoCommits());
testConn.close();
} while ((useLocTransSt = !useLocTransSt) || (useElideSetAC = !useElideSetAC));
@@ -9849,4 +9853,70 @@ public class ConnectionRegressionTest extends BaseTestCase {
assertEquals(testCase, 1, this.rs.getInt(1));
} while (useLocTransSt = !useLocTransSt);
}
+
+ /**
+ * Tests fix for Bug#70785 - MySQL Connector/J inconsistent init state for autocommit.
+ */
+ public void testBug70785() throws Exception {
+ // Make sure that both client and server have autocommit turned on.
+ assertTrue(this.conn.getAutoCommit());
+ this.rs = this.stmt.executeQuery("SELECT @@session.autocommit");
+ this.rs.next();
+ assertTrue(this.rs.getBoolean(1));
+
+ if (!versionMeetsMinimum(5, 5)) {
+ return;
+ }
+ this.rs = this.stmt.executeQuery("SELECT @@global.init_connect");
+ this.rs.next();
+ String originalInitConnect = this.rs.getString(1);
+ this.stmt.execute("SET @@global.init_connect='SET @testBug70785=1'"); // Server variable init_connect cannot be empty for this test.
+
+ this.rs = this.stmt.executeQuery("SELECT @@global.autocommit");
+ this.rs.next();
+ boolean originalAutoCommit = this.rs.getBoolean(1);
+ boolean autoCommit = originalAutoCommit;
+
+ int n = 0;
+ try {
+ do {
+ this.stmt.execute("SET @@global.autocommit=" + (autoCommit ? 1 : 0));
+
+ boolean cacheServerConf = false;
+ boolean useLocTransSt = false;
+ boolean elideSetAutoCommit = false;
+ do {
+ final String testCase = String.format("Case: [AutoCommit: %s, CacheSrvConf: %s, LocTransSt: %s, ElideSetAC: %s ]", autoCommit ? "Y" : "N",
+ cacheServerConf ? "Y" : "N", useLocTransSt ? "Y" : "N", elideSetAutoCommit ? "Y" : "N");
+ final Properties props = new Properties();
+ props.setProperty("cacheServerConfiguration", Boolean.toString(cacheServerConf));
+ props.setProperty("useLocalTransactionState", Boolean.toString(useLocTransSt));
+ props.setProperty("elideSetAutoCommits", Boolean.toString(elideSetAutoCommit));
+
+ if (cacheServerConf) {
+ n++;
+ }
+ String uniqueUrl = dbUrl + "&testBug70785=" + n; // Make sure that the first connection will be a cache miss and the second a cache hit.
+ Connection testConn1 = getConnectionWithProps(uniqueUrl, props);
+ Connection testConn2 = getConnectionWithProps(uniqueUrl, props);
+
+ assertTrue(testCase, testConn1.getAutoCommit());
+ this.rs = testConn1.createStatement().executeQuery("SELECT @@session.autocommit");
+ this.rs.next();
+ assertTrue(testCase, this.rs.getBoolean(1));
+
+ assertTrue(testCase, testConn2.getAutoCommit());
+ this.rs = testConn2.createStatement().executeQuery("SELECT @@session.autocommit");
+ this.rs.next();
+ assertTrue(testCase, this.rs.getBoolean(1));
+
+ testConn1.close();
+ testConn2.close();
+ } while ((cacheServerConf = !cacheServerConf) || (useLocTransSt = !useLocTransSt) || (elideSetAutoCommit = !elideSetAutoCommit));
+ } while ((autoCommit = !autoCommit) != originalAutoCommit);
+ } finally {
+ this.stmt.execute("SET @@global.init_connect='" + originalInitConnect + "'");
+ this.stmt.execute("SET @@global.autocommit=" + (originalAutoCommit ? 1 : 0));
+ }
+ }
}
diff --git a/src/testsuite/regression/StatementRegressionTest.java b/src/testsuite/regression/StatementRegressionTest.java
index de1b327..31b4f55 100644
--- a/src/testsuite/regression/StatementRegressionTest.java
+++ b/src/testsuite/regression/StatementRegressionTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -8064,4 +8064,80 @@ public class StatementRegressionTest extends BaseTestCase {
assertEquals(testCase, expectedExecCount, actualExecCount);
assertEquals(testCase, expectedCloseCount, actualCloseCount);
}
+
+ /**
+ * Test fix for Bug#81706 - NullPointerException in driver.
+ */
+ public void testBug81706() throws Exception {
+ boolean useSPS = false;
+ boolean cacheRsMd = false;
+ boolean readOnly = false;
+
+ do {
+ final String testCase = String.format("Case [SPS: %s, CacheRsMd: %s, Read-only: %s]", useSPS ? "Y" : "N", cacheRsMd ? "Y" : "N",
+ readOnly ? "Y" : "N");
+
+ Properties props = new Properties();
+ props.setProperty("useServerPrepStmts", Boolean.toString(useSPS));
+ props.setProperty("cacheResultSetMetadata", Boolean.toString(cacheRsMd));
+ props.setProperty("statementInterceptors", TestBug81706StatementInterceptor.class.getName());
+
+ Connection testConn = getConnectionWithProps(props);
+ testConn.setReadOnly(readOnly);
+ Statement testStmt;
+ PreparedStatement testPstmt;
+
+ TestBug81706StatementInterceptor.isActive = true;
+ TestBug81706StatementInterceptor.testCase = testCase;
+
+ // Statement.executeQuery();
+ testStmt = testConn.createStatement();
+ testStmt.setFetchSize(Integer.MIN_VALUE);
+ testStmt.executeQuery("/* ping */");
+ testStmt.close();
+
+ // Statemente.execute();
+ testStmt = testConn.createStatement();
+ testStmt.setFetchSize(Integer.MIN_VALUE);
+ testStmt.execute("/* ping */");
+ testStmt.close();
+
+ // PreparedStatement.executeQuery();
+ testPstmt = testConn.prepareStatement("/* ping */");
+ assertFalse(testCase + ": Not the right Statement type.", testPstmt instanceof ServerPreparedStatement);
+ testPstmt.setFetchSize(Integer.MIN_VALUE);
+ testPstmt.executeQuery();
+ testPstmt.close();
+
+ // PreparedStatement.execute();
+ testPstmt = testConn.prepareStatement("/* ping */");
+ assertFalse(testCase + ": Not the right Statement type.", testPstmt instanceof ServerPreparedStatement);
+ testPstmt.setFetchSize(Integer.MIN_VALUE);
+ testPstmt.execute();
+ testPstmt.close();
+
+ TestBug81706StatementInterceptor.isActive = false;
+ testConn.close();
+
+ } while ((useSPS = !useSPS) || (cacheRsMd = !cacheRsMd) || (readOnly = !readOnly)); // Cycle through all possible combinations.
+ }
+
+ public static class TestBug81706StatementInterceptor extends BaseStatementInterceptor {
+ public static boolean isActive = false;
+ public static String testCase = "";
+
+ @Override
+ public ResultSetInternalMethods preProcess(String sql, com.mysql.jdbc.Statement interceptedStatement, com.mysql.jdbc.Connection connection)
+ throws SQLException {
+ if (isActive) {
+ String query = sql;
+ if (query == null && interceptedStatement instanceof com.mysql.jdbc.PreparedStatement) {
+ query = interceptedStatement.toString();
+ query = query.substring(query.indexOf(':') + 2);
+ }
+ fail(testCase + ": Unexpected query executed - " + query);
+ }
+ return super.preProcess(sql, interceptedStatement, connection);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/testsuite/regression/SyntaxRegressionTest.java b/src/testsuite/regression/SyntaxRegressionTest.java
index 0416afb..4f73121 100644
--- a/src/testsuite/regression/SyntaxRegressionTest.java
+++ b/src/testsuite/regression/SyntaxRegressionTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -30,13 +30,20 @@ import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
+import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.NonRegisteringDriver;
import com.mysql.jdbc.StringUtils;
import com.mysql.jdbc.Util;
@@ -336,15 +343,36 @@ public class SyntaxRegressionTest extends BaseTestCase {
createTable("testExchangePartition2", "LIKE testExchangePartition1");
this.stmt.executeUpdate("ALTER TABLE testExchangePartition2 REMOVE PARTITIONING");
- if (versionMeetsMinimum(5, 7, 4)) {
+
+ // Using Statement, with and without validation.
+ if (versionMeetsMinimum(5, 7, 5)) {
+ this.stmt.executeUpdate("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2 WITH VALIDATION");
+ this.stmt.executeUpdate("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2 WITHOUT VALIDATION");
+ } else if (versionMeetsMinimum(5, 7, 4)) {
this.stmt.executeUpdate("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
} else {
+ this.stmt.executeUpdate("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
this.stmt.executeUpdate("ALTER IGNORE TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
}
- if (versionMeetsMinimum(5, 7, 4)) {
+ // Using Client PreparedStatement, with validation.
+ if (versionMeetsMinimum(5, 7, 5)) {
+ this.pstmt = this.conn
+ .prepareStatement("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2 WITH VALIDATION");
+ } else if (versionMeetsMinimum(5, 7, 4)) {
this.pstmt = this.conn.prepareStatement("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
} else {
+ this.pstmt = this.conn.prepareStatement("ALTER TABLE testExchangePartition1 " + "EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
+ }
+ assertEquals(Util.isJdbc4() ? Class.forName(Util.isJdbc42() ? "com.mysql.jdbc.JDBC42PreparedStatement" : "com.mysql.jdbc.JDBC4PreparedStatement")
+ : com.mysql.jdbc.PreparedStatement.class, this.pstmt.getClass());
+ this.pstmt.executeUpdate();
+
+ // Using Client PreparedStatement, without validation.
+ if (versionMeetsMinimum(5, 7, 5)) {
+ this.pstmt = this.conn
+ .prepareStatement("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2 WITHOUT VALIDATION");
+ } else {
this.pstmt = this.conn
.prepareStatement("ALTER IGNORE TABLE testExchangePartition1 " + "EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
}
@@ -355,7 +383,12 @@ public class SyntaxRegressionTest extends BaseTestCase {
Connection testConn = null;
try {
testConn = getConnectionWithProps("useServerPrepStmts=true,emulateUnsupportedPstmts=false");
- if (versionMeetsMinimum(5, 7, 4)) {
+
+ // Using Server PreparedStatement, with validation.
+ if (versionMeetsMinimum(5, 7, 5)) {
+ this.pstmt = testConn
+ .prepareStatement("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2 WITH VALIDATION");
+ } else if (versionMeetsMinimum(5, 7, 4)) {
this.pstmt = testConn.prepareStatement("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
} else {
this.pstmt = testConn
@@ -366,6 +399,19 @@ public class SyntaxRegressionTest extends BaseTestCase {
? Class.forName(Util.isJdbc42() ? "com.mysql.jdbc.JDBC42ServerPreparedStatement" : "com.mysql.jdbc.JDBC4ServerPreparedStatement")
: com.mysql.jdbc.ServerPreparedStatement.class, this.pstmt.getClass());
this.pstmt.executeUpdate();
+
+ // Using Server PreparedStatement, without validation.
+ if (versionMeetsMinimum(5, 7, 5)) {
+ this.pstmt = testConn
+ .prepareStatement("ALTER TABLE testExchangePartition1 EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2 WITHOUT VALIDATION");
+ } else {
+ this.pstmt = testConn.prepareStatement("ALTER TABLE testExchangePartition1 " + "EXCHANGE PARTITION p1 WITH TABLE testExchangePartition2");
+
+ }
+ assertEquals(Util.isJdbc4()
+ ? Class.forName(Util.isJdbc42() ? "com.mysql.jdbc.JDBC42ServerPreparedStatement" : "com.mysql.jdbc.JDBC4ServerPreparedStatement")
+ : com.mysql.jdbc.ServerPreparedStatement.class, this.pstmt.getClass());
+ this.pstmt.executeUpdate();
} finally {
if (testConn != null) {
testConn.close();
@@ -380,15 +426,36 @@ public class SyntaxRegressionTest extends BaseTestCase {
* @throws SQLException
*/
public void testExplicitPartitions() throws Exception {
-
if (versionMeetsMinimum(5, 6, 5)) {
- Connection c = null;
+
String datadir = null;
+ this.rs = this.stmt.executeQuery("SHOW VARIABLES WHERE Variable_name='datadir'");
+ this.rs.next();
+ datadir = this.rs.getString(2);
+ if (datadir != null) {
+ datadir = new File(datadir).getCanonicalPath();
+ }
+
+ this.rs = this.stmt.executeQuery("SHOW VARIABLES WHERE Variable_name='secure_file_priv'");
+ this.rs.next();
+ String fileprivdir = this.rs.getString(2);
+ if ("NULL".equalsIgnoreCase(this.rs.getString(2))) {
+ fail("To run this test the server needs to be started with the option\"--secure-file-priv=\"");
+ } else if (fileprivdir.length() > 0) {
+ fileprivdir = new File(fileprivdir).getCanonicalPath();
+ if (!datadir.equals(fileprivdir)) {
+ fail("To run this test the server option\"--secure-file-priv=\" needs to be empty or to match the server's data directory.");
+ }
+ }
+
+ Connection c = null;
Properties props = new NonRegisteringDriver().parseURL(dbUrl, null);
String dbname = props.getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY);
props = new Properties();
props.setProperty("useServerPrepStmts", "true");
+
+ boolean exceptionCaugth = false;
try {
this.stmt.executeUpdate("SET @old_default_storage_engine = @@default_storage_engine");
@@ -453,14 +520,10 @@ public class SyntaxRegressionTest extends BaseTestCase {
this.stmt.executeUpdate("UNLOCK TABLES");
// Test LOAD
- this.rs = this.stmt.executeQuery("SHOW VARIABLES WHERE Variable_name='datadir'");
- this.rs.next();
- datadir = this.rs.getString(2);
-
if (dbname == null) {
fail("No database selected");
} else {
- File f = new File(datadir + dbname + File.separator + "loadtestExplicitPartitions.txt");
+ File f = new File(datadir + File.separator + dbname + File.separator + "loadtestExplicitPartitions.txt");
if (f.exists()) {
f.delete();
}
@@ -606,6 +669,10 @@ public class SyntaxRegressionTest extends BaseTestCase {
this.stmt.executeUpdate("SET @@default_storage_engine = @old_default_storage_engine");
+ } catch (SQLException e) {
+ exceptionCaugth = true;
+ fail(e.getMessage());
+
} finally {
this.stmt.executeUpdate("DROP TABLE IF EXISTS testExplicitPartitions, testExplicitPartitions2, testExplicitPartitions3");
@@ -613,11 +680,11 @@ public class SyntaxRegressionTest extends BaseTestCase {
c.close();
}
if (datadir != null) {
- File f = new File(datadir + dbname + File.separator + "loadtestExplicitPartitions.txt");
+ File f = new File(datadir + File.separator + dbname + File.separator + "loadtestExplicitPartitions.txt");
if (f.exists()) {
f.deleteOnExit();
- } else {
- fail("File " + datadir + dbname + File.separator + "loadtestExplicitPartitions.txt cannot be deleted."
+ } else if (!exceptionCaugth) {
+ fail("File " + datadir + File.separator + dbname + File.separator + "loadtestExplicitPartitions.txt cannot be deleted."
+ "You should run server and tests on the same filesystem.");
}
}
@@ -626,36 +693,6 @@ public class SyntaxRegressionTest extends BaseTestCase {
}
/**
- * WL#1326 - GIS: Precise spatial operations
- *
- * GIS functions added in 5.6GA: ST_Intersection(g1 geometry, g2 geometry); ST_Difference(g1 geometry, g2 geometry);
- * ST_Union(g1 geometry, g2 geometry); ST_SymDifference(g1 geometry, g2 geometry); ST_Buffer(g1 geometry, d
- * numeric).
- *
- * @throws SQLException
- */
- public void testGISPreciseSpatialFunctions() throws Exception {
- if (!versionMeetsMinimum(5, 6)) {
- return;
- }
-
- String[] querySamples = new String[] {
- "SELECT ST_AsText(ST_Intersection(ST_GeomFromText('POLYGON((0 0, 8 0, 4 6, 0 0))'), ST_GeomFromText('POLYGON((0 3, 8 3, 4 9, 0 3))')))",
- "SELECT ST_AsText(ST_Difference(ST_GeomFromText('POLYGON((0 0, 8 0, 4 6, 0 0))'), ST_GeomFromText('POLYGON((0 3, 8 3, 4 9, 0 3))')))",
- "SELECT ST_AsText(ST_Union(ST_GeomFromText('POLYGON((0 0, 8 0, 4 6, 0 0))'), ST_GeomFromText('POLYGON((0 3, 8 3, 4 9, 0 3))')))",
- "SELECT ST_AsText(ST_SymDifference(ST_GeomFromText('POLYGON((0 0, 8 0, 4 6, 0 0))'), ST_GeomFromText('POLYGON((0 3, 8 3, 4 9, 0 3))')))",
- "SELECT ST_AsText(ST_Buffer(ST_GeomFromText('POLYGON((0 0, 8 0, 4 6, 0 0))'), 0.5))",
- "SELECT ST_Distance(ST_GeomFromText('POLYGON((0 0, 8 0, 4 6, 0 0))'), ST_GeomFromText('POLYGON((0 10, 8 10, 4 16, 0 10))'))" };
-
- for (String query : querySamples) {
- this.rs = this.stmt.executeQuery(query);
- assertTrue("Query should return at least one row.", this.rs.next());
- assertFalse("Query should return only one row.", this.rs.next());
- this.rs.close();
- }
- }
-
- /**
* WL#5787 - IPv6-capable INET_ATON and INET_NTOA functions
*
* IPv6 functions added in 5.6GA: INET6_ATON(ip) and INET6_NTOA(ip).
@@ -1218,4 +1255,713 @@ public class SyntaxRegressionTest extends BaseTestCase {
assertEquals(processesHint ? 1 : 0, this.rs.getInt(1));
assertFalse(this.rs.next());
}
+
+ /**
+ * WL#6205 - InnoDB: Implement CREATE TABLESPACE for general use.
+ *
+ * Tests support for new CREATE TABLESPACE syntax that extends this feature to InnoDB.
+ *
+ * CREATE TABLESPACE tablespace_name ADD DATAFILE 'file_name' [FILE_BLOCK_SIZE = value] [ENGINE [=] engine_name]
+ */
+ public void testCreateTablespace() throws Exception {
+ if (!versionMeetsMinimum(5, 7, 6)) {
+ return;
+ }
+
+ try {
+ this.stmt.execute("CREATE TABLESPACE testTs1 ADD DATAFILE 'testTs1.ibd'");
+ this.stmt.execute("CREATE TABLESPACE testTs2 ADD DATAFILE 'testTs2.ibd'");
+
+ testCreateTablespaceCheckTablespaces(2);
+
+ createTable("testTs1Tbl1", "(id INT) TABLESPACE testTs1");
+ createTable("testTs1Tbl2", "(id INT) TABLESPACE testTs1");
+ createTable("testTs2Tbl1", "(id INT) TABLESPACE testTs2");
+
+ testCreateTablespaceCheckTables("testTs1", 2);
+ testCreateTablespaceCheckTables("testTs2", 1);
+
+ this.stmt.execute("ALTER TABLE testTs1Tbl2 TABLESPACE testTs2");
+
+ testCreateTablespaceCheckTables("testTs1", 1);
+ testCreateTablespaceCheckTables("testTs2", 2);
+
+ dropTable("testTs1Tbl1");
+ dropTable("testTs1Tbl2");
+ dropTable("testTs2Tbl1");
+
+ testCreateTablespaceCheckTables("testTs1", 0);
+ testCreateTablespaceCheckTables("testTs2", 0);
+
+ } finally {
+ // Make sure the tables are dropped before the tablespaces.
+ dropTable("testTs1Tbl1");
+ dropTable("testTs1Tbl2");
+ dropTable("testTs2Tbl1");
+
+ this.stmt.execute("DROP TABLESPACE testTs1");
+ this.stmt.execute("DROP TABLESPACE testTs2");
+
+ testCreateTablespaceCheckTablespaces(0);
+ }
+ }
+
+ private void testCreateTablespaceCheckTablespaces(int expectedTsCount) throws Exception {
+ this.rs = this.stmt.executeQuery("SELECT COUNT(*) FROM information_schema.innodb_sys_tablespaces WHERE name LIKE 'testTs_'");
+ assertTrue(this.rs.next());
+ assertEquals(expectedTsCount, this.rs.getInt(1));
+ }
+
+ private void testCreateTablespaceCheckTables(String tablespace, int expectedTblCount) throws Exception {
+ this.rs = this.stmt.executeQuery("SELECT COUNT(*) FROM information_schema.innodb_sys_tables a, information_schema.innodb_sys_tablespaces b "
+ + "WHERE a.space = b.space AND b.name = '" + tablespace + "'");
+ assertTrue(this.rs.next());
+ assertEquals(expectedTblCount, this.rs.getInt(1));
+ }
+
+ /**
+ * WL#6747 - InnoDB: make fill factor settable.
+ *
+ * Tests support for new syntax for setting indices MERGE_THRESHOLD on CREATE TABLE.
+ *
+ * index_option:
+ * COMMENT 'MERGE_THRESHOLD=n'
+ */
+ public void testSetMergeThreshold() throws Exception {
+ if (!versionMeetsMinimum(5, 7, 6)) {
+ return;
+ }
+
+ Map<String, Integer> keyMergeThresholds = new HashMap<String, Integer>();
+ keyMergeThresholds.put("k2", 45);
+ keyMergeThresholds.put("k3", 40);
+ keyMergeThresholds.put("k23", 35);
+ keyMergeThresholds.put("k24", 30);
+ int tableMergeThreshold = 25;
+
+ // Create table with both table and per index merge thresholds.
+ createTable("testSetMergeThreshold",
+ "(c1 INT, c2 INT, c3 INT, c4 INT, KEY k1 (c1), KEY k2 (c2) COMMENT 'MERGE_THRESHOLD=" + keyMergeThresholds.get("k2")
+ + "', KEY k3 (c3) COMMENT 'MERGE_THRESHOLD=" + keyMergeThresholds.get("k3") + "', KEY k23 (c2, c3) COMMENT 'MERGE_THRESHOLD="
+ + keyMergeThresholds.get("k23") + "', KEY k24 (c2, c4) COMMENT 'MERGE_THRESHOLD=" + keyMergeThresholds.get("k24")
+ + "') COMMENT 'MERGE_THRESHOLD=" + tableMergeThreshold + "'");
+ testSetMergeThresholdIndices(tableMergeThreshold, keyMergeThresholds);
+
+ // Change table's merge threshold.
+ tableMergeThreshold++;
+ this.stmt.execute("ALTER TABLE testSetMergeThreshold COMMENT 'MERGE_THRESHOLD=" + tableMergeThreshold + "'");
+ testSetMergeThresholdIndices(tableMergeThreshold, keyMergeThresholds);
+
+ // Change index' merge threshold.
+ keyMergeThresholds.put("k3", 41);
+ this.stmt.execute("ALTER TABLE testSetMergeThreshold DROP KEY k3");
+ this.stmt.execute("ALTER TABLE testSetMergeThreshold ADD KEY k3 (c3) COMMENT 'MERGE_THRESHOLD=" + keyMergeThresholds.get("k3") + "'");
+ testSetMergeThresholdIndices(tableMergeThreshold, keyMergeThresholds);
+
+ // Add new index with a non-default merge threshold value.
+ keyMergeThresholds.put("k123", 15);
+ this.stmt.execute("CREATE INDEX k123 ON testSetMergeThreshold (c1, c2, c3) COMMENT 'MERGE_THRESHOLD=" + keyMergeThresholds.get("k123") + "'");
+ testSetMergeThresholdIndices(tableMergeThreshold, keyMergeThresholds);
+ }
+
+ private void testSetMergeThresholdIndices(int defaultMergeThreshold, Map<String, Integer> keyMergeThresholds) throws Exception {
+ this.rs = this.stmt.executeQuery("SELECT name, merge_threshold FROM information_schema.innodb_sys_indexes WHERE table_id = "
+ + "(SELECT table_id FROM information_schema.innodb_sys_tables WHERE name = '" + this.conn.getCatalog() + "/testSetMergeThreshold')");
+
+ while (this.rs.next()) {
+ int expected = keyMergeThresholds.containsKey(this.rs.getString(1)) ? keyMergeThresholds.get(this.rs.getString(1)) : defaultMergeThreshold;
+ assertEquals("MERGE_THRESHOLD for index " + this.rs.getString(1), expected, this.rs.getInt(2));
+ }
+ assertTrue(this.rs.last());
+ assertTrue(this.rs.getRow() >= keyMergeThresholds.size());
+ }
+
+ /**
+ * WL#7696 - InnoDB: Transparent page compression.
+ *
+ * Tests COMPRESSION clause in CREATE|ALTER TABLE syntax.
+ *
+ * table_option: (...) | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'}
+ */
+ public void testTableCompression() throws Exception {
+ if (!versionMeetsMinimum(5, 7, 8)) {
+ return;
+ }
+
+ // Create table with 'zlib' compression.
+ createTable("testTableCompression", "(c VARCHAR(15000)) COMPRESSION='ZLIB'");
+
+ this.rs = this.stmt.executeQuery("show create table testTableCompression");
+ assertTrue(this.rs.next());
+ assertTrue(StringUtils.indexOfIgnoreCase(this.rs.getString(2), "COMPRESSION='ZLIB'") >= 0);
+
+ // Alter table compression to 'lz4'.
+ this.stmt.execute("ALTER TABLE testTableCompression COMPRESSION='LZ4'");
+
+ this.rs = this.stmt.executeQuery("show create table testTableCompression");
+ assertTrue(this.rs.next());
+ assertTrue(StringUtils.indexOfIgnoreCase(this.rs.getString(2), "COMPRESSION='LZ4'") >= 0);
+
+ // Alter table compression to 'none'.
+ this.stmt.execute("ALTER TABLE testTableCompression COMPRESSION='NONE'");
+
+ this.rs = this.stmt.executeQuery("show create table testTableCompression");
+ assertTrue(this.rs.next());
+ assertTrue(StringUtils.indexOfIgnoreCase(this.rs.getString(2), "COMPRESSION='NONE'") >= 0);
+ }
+
+ /**
+ * WL#1326 - GIS: Precise spatial operations
+ * WL#8055 - Consistent naming scheme for GIS functions - Deprecation
+ * WL#8034 - More user friendly GIS functions
+ * WL#7541 - GIS MBR spatial operations enhancement
+ * (...)
+ *
+ * Test syntax for all GIS functions.
+ */
+ public void testGisFunctions() throws Exception {
+ final String wktPoint = "'POINT(0 0)'";
+ final String wktLineString = "'LINESTRING(0 0, 8 0, 4 6, 0 0)'";
+ final String wktPolygon = "'POLYGON((0 0, 8 0, 4 6, 0 0), (4 1, 6 0, 5 3, 4 1))'";
+ final String wktMultiPoint = "'MULTIPOINT(0 0, 8 0, 4 6)'";
+ final String wktMultiLineString = "'MULTILINESTRING((0 0, 8 0, 4 6, 0 0), (4 1, 6 0, 5 3, 4 1))'";
+ final String wktMultiPolygon = "'MULTIPOLYGON(((0 0, 8 0, 4 6, 0 0), (4 1, 6 0, 5 3, 4 1)), ((0 3, 8 3, 4 9, 0 3)))'";
+ final String wktGeometryCollection = "'GEOMETRYCOLLECTION(POINT(8 0), LINESTRING(0 0, 8 0, 4 6, 0 0), POLYGON((0 3, 8 3, 4 9, 0 3)))'";
+
+ final String wkbPoint1 = "Point(0, 0)";
+ final String wkbPoint2 = "Point(8, 0)";
+ final String wkbPoint3 = "Point(4, 6)";
+ final String wkbPoint4 = "Point(4, 1)";
+ final String wkbPoint5 = "Point(6, 0)";
+ final String wkbPoint6 = "Point(5, 3)";
+ final String wkbPoint7 = "Point(0, 3)";
+ final String wkbPoint8 = "Point(8, 3)";
+ final String wkbPoint9 = "Point(4, 9)";
+ final String wkbLineString1 = String.format("LineString(%s, %s, %s, %s)", wkbPoint1, wkbPoint2, wkbPoint3, wkbPoint1);
+ final String wkbLineString2 = String.format("LineString(%s, %s, %s, %s)", wkbPoint4, wkbPoint5, wkbPoint6, wkbPoint4);
+ final String wkbLineString3 = String.format("LineString(%s, %s, %s, %s)", wkbPoint7, wkbPoint8, wkbPoint9, wkbPoint7);
+ final String wkbPolygon1 = String.format("Polygon(%s, %s)", wkbLineString1, wkbLineString2);
+ final String wkbPolygon2 = String.format("Polygon(%s)", wkbLineString3);
+ final String wkbMultiPoint = String.format("MultiPoint(%s, %s, %s)", wkbPoint1, wkbPoint2, wkbPoint3);
+ final String wkbMultiLineString = String.format("MultiLineString(%s, %s)", wkbLineString1, wkbLineString2);
+ final String wkbMultiPolygon = String.format("MultiPolygon(%s, %s)", wkbPolygon1, wkbPolygon2);
+ final String wkbGeometryCollection = String.format("GeometryCollection(%s, %s, %s)", wkbPoint2, wkbLineString1, wkbPolygon2);
+
+ final Map<String, String> args = new HashMap<String, String>();
+ args.put("gcWkt", wktGeometryCollection);
+ args.put("gWkt", wktGeometryCollection);
+ args.put("lsWkt", wktLineString);
+ args.put("mlsWkt", wktMultiLineString);
+ args.put("mptWkt", wktMultiPoint);
+ args.put("mplWkt", wktMultiPolygon);
+ args.put("ptWkt", wktPoint);
+ args.put("plWkt", wktPolygon);
+ args.put("gcWkb", wkbGeometryCollection);
+ args.put("gWkb", wkbGeometryCollection);
+ args.put("lsWkb", wkbLineString1);
+ args.put("mlsWkb", wkbMultiLineString);
+ args.put("mptWkb", wkbMultiPoint);
+ args.put("mplWkb", wkbMultiPolygon);
+ args.put("ptWkb", wkbPoint1);
+ args.put("plWkb", wkbPolygon1);
+ args.put("g1", wkbPolygon1);
+ args.put("g2", wkbPolygon2);
+ args.put("pt1", wkbPoint1);
+ args.put("pt2", wkbPoint2);
+ args.put("ls1", wkbLineString1);
+ args.put("ls2", wkbLineString2);
+ args.put("pl1", wkbPolygon1);
+ args.put("pl2", wkbPolygon2);
+ args.put("g", wkbGeometryCollection);
+ args.put("pt", wkbPoint3);
+ args.put("ls", wkbLineString1);
+ args.put("pl", wkbPolygon1);
+ args.put("mpl", wkbMultiPolygon);
+ args.put("gc", wkbGeometryCollection);
+ args.put("gh", "'s14f5h28wc04jsq093jd'");
+ args.put("js",
+ "'{\"type\": \"GeometryCollection\", \"geometries\": [" + //
+ "{\"type\": \"Point\", \"coordinates\": [8, 0]}, " + //
+ "{\"type\": \"LineString\", \"coordinates\": [[0, 0], [8, 0], [4, 6], [0, 0]]}, " + //
+ "{\"type\": \"Polygon\", \"coordinates\": [[[0, 3], [8, 3], [4, 9], [0, 3]]]}]}'");
+
+ final class GisFunction {
+ String function;
+ int low_version_maj;
+ int low_version_min;
+ int low_version_sub;
+ int hi_version_maj;
+ int hi_version_min;
+ int hi_version_sub;
+ List<String> args;
+
+ GisFunction(String function, int low_version_maj, int low_version_min, int low_version_sub, int hi_version_maj, int hi_version_min,
+ int hi_version_sub, String... args) {
+ this.function = function;
+ this.low_version_maj = low_version_maj;
+ this.low_version_min = low_version_min;
+ this.low_version_sub = low_version_sub;
+ this.hi_version_maj = hi_version_maj;
+ this.hi_version_min = hi_version_min;
+ this.hi_version_sub = hi_version_sub;
+ this.args = Arrays.asList(args);
+ }
+ }
+ final List<GisFunction> gisFunctions = new ArrayList<GisFunction>();
+ // Functions That Create Geometry Values from WKT Values
+ gisFunctions.add(new GisFunction("GeomCollFromText", 5, 5, 1, 5, 7, 6, "gcWkt"));
+ gisFunctions.add(new GisFunction("GeometryCollectionFromText", 5, 5, 1, 5, 7, 6, "gcWkt"));
+ gisFunctions.add(new GisFunction("GeomFromText", 5, 5, 1, 5, 7, 6, "gWkt"));
+ gisFunctions.add(new GisFunction("GeometryFromText", 5, 5, 1, 5, 7, 6, "gWkt"));
+ gisFunctions.add(new GisFunction("LineFromText", 5, 5, 1, 5, 7, 6, "lsWkt"));
+ gisFunctions.add(new GisFunction("LineStringFromText", 5, 5, 1, 5, 7, 6, "lsWkt"));
+ gisFunctions.add(new GisFunction("MLineFromText", 5, 5, 1, 5, 7, 6, "mlsWkt"));
+ gisFunctions.add(new GisFunction("MultiLineStringFromText", 5, 5, 1, 5, 7, 6, "mlsWkt"));
+ gisFunctions.add(new GisFunction("MPointFromText", 5, 5, 1, 5, 7, 6, "mptWkt"));
+ gisFunctions.add(new GisFunction("MultiPointFromText", 5, 5, 1, 5, 7, 6, "mptWkt"));
+ gisFunctions.add(new GisFunction("MPolyFromText", 5, 5, 1, 5, 7, 6, "mplWkt"));
+ gisFunctions.add(new GisFunction("MultiPolygonFromText", 5, 5, 1, 5, 7, 6, "mplWkt"));
+ gisFunctions.add(new GisFunction("PointFromText", 5, 5, 1, 5, 7, 6, "ptWkt"));
+ gisFunctions.add(new GisFunction("PolyFromText", 5, 5, 1, 5, 7, 6, "plWkt"));
+ gisFunctions.add(new GisFunction("PolygonFromText", 5, 5, 1, 5, 7, 6, "plWkt"));
+ gisFunctions.add(new GisFunction("ST_GeomCollFromText", 5, 6, 1, 0, 0, 0, "gcWkt"));
+ gisFunctions.add(new GisFunction("ST_GeometryCollectionFromText", 5, 6, 1, 0, 0, 0, "gcWkt"));
+ gisFunctions.add(new GisFunction("ST_GeomCollFromTxt", 5, 7, 6, 0, 0, 0, "gcWkt"));
+ gisFunctions.add(new GisFunction("ST_GeomFromText", 5, 6, 1, 0, 0, 0, "gWkt"));
+ gisFunctions.add(new GisFunction("ST_GeometryFromText", 5, 6, 1, 0, 0, 0, "gWkt"));
+ gisFunctions.add(new GisFunction("ST_LineFromText", 5, 6, 1, 0, 0, 0, "lsWkt"));
+ gisFunctions.add(new GisFunction("ST_LineStringFromText", 5, 6, 1, 0, 0, 0, "lsWkt"));
+ gisFunctions.add(new GisFunction("ST_MLineFromText", 5, 7, 6, 0, 0, 0, "mlsWkt"));
+ gisFunctions.add(new GisFunction("ST_MultiLineStringFromText", 5, 7, 6, 0, 0, 0, "mlsWkt"));
+ gisFunctions.add(new GisFunction("ST_MPointFromText", 5, 7, 6, 0, 0, 0, "mptWkt"));
+ gisFunctions.add(new GisFunction("ST_MultiPointFromText", 5, 7, 6, 0, 0, 0, "mptWkt"));
+ gisFunctions.add(new GisFunction("ST_MPolyFromText", 5, 7, 6, 0, 0, 0, "mplWkt"));
+ gisFunctions.add(new GisFunction("ST_MultiPolygonFromText", 5, 7, 6, 0, 0, 0, "mplWkt"));
+ gisFunctions.add(new GisFunction("ST_PointFromText", 5, 6, 1, 0, 0, 0, "ptWkt"));
+ gisFunctions.add(new GisFunction("ST_PolyFromText", 5, 6, 1, 0, 0, 0, "plWkt"));
+ gisFunctions.add(new GisFunction("ST_PolygonFromText", 5, 6, 1, 0, 0, 0, "plWkt"));
+ // Functions That Create Geometry Values from WKB Values
+ gisFunctions.add(new GisFunction("GeomCollFromWKB", 5, 5, 1, 5, 7, 6, "gcWkb"));
+ gisFunctions.add(new GisFunction("GeometryCollectionFromWKB", 5, 5, 1, 5, 7, 6, "gcWkb"));
+ gisFunctions.add(new GisFunction("GeomFromWKB", 5, 5, 1, 5, 7, 6, "gWkb"));
+ gisFunctions.add(new GisFunction("GeometryFromWKB", 5, 5, 1, 5, 7, 6, "gWkb"));
+ gisFunctions.add(new GisFunction("LineFromWKB", 5, 5, 1, 5, 7, 6, "lsWkb"));
+ gisFunctions.add(new GisFunction("LineStringFromWKB", 5, 5, 1, 5, 7, 6, "lsWkb"));
+ gisFunctions.add(new GisFunction("MLineFromWKB", 5, 5, 1, 5, 7, 6, "mlsWkb"));
+ gisFunctions.add(new GisFunction("MultiLineStringFromWKB", 5, 5, 1, 5, 7, 6, "mlsWkb"));
+ gisFunctions.add(new GisFunction("MPointFromWKB", 5, 5, 1, 5, 7, 6, "mptWkb"));
+ gisFunctions.add(new GisFunction("MultiPointFromWKB", 5, 5, 1, 5, 7, 6, "mptWkb"));
+ gisFunctions.add(new GisFunction("MPolyFromWKB", 5, 5, 1, 5, 7, 6, "mplWkb"));
+ gisFunctions.add(new GisFunction("MultiPolygonFromWKB", 5, 5, 1, 5, 7, 6, "mplWkb"));
+ gisFunctions.add(new GisFunction("PointFromWKB", 5, 5, 1, 5, 7, 6, "ptWkb"));
+ gisFunctions.add(new GisFunction("PolyFromWKB", 5, 5, 1, 5, 7, 6, "plWkb"));
+ gisFunctions.add(new GisFunction("PolygonFromWKB", 5, 5, 1, 5, 7, 6, "plWkb"));
+ gisFunctions.add(new GisFunction("ST_GeomCollFromWKB", 5, 6, 1, 0, 0, 0, "gcWkb"));
+ gisFunctions.add(new GisFunction("ST_GeometryCollectionFromWKB", 5, 6, 1, 0, 0, 0, "gcWkb"));
+ gisFunctions.add(new GisFunction("ST_GeomFromWKB", 5, 6, 1, 0, 0, 0, "gWkb"));
+ gisFunctions.add(new GisFunction("ST_GeometryFromWKB", 5, 6, 1, 0, 0, 0, "gWkb"));
+ gisFunctions.add(new GisFunction("ST_LineFromWKB", 5, 6, 1, 0, 0, 0, "lsWkb"));
+ gisFunctions.add(new GisFunction("ST_LineStringFromWKB", 5, 6, 1, 0, 0, 0, "lsWkb"));
+ gisFunctions.add(new GisFunction("ST_MLineFromWKB", 5, 7, 6, 0, 0, 0, "mlsWkb"));
+ gisFunctions.add(new GisFunction("ST_MultiLineStringFromWKB", 5, 7, 6, 0, 0, 0, "mlsWkb"));
+ gisFunctions.add(new GisFunction("ST_MPointFromWKB", 5, 7, 6, 0, 0, 0, "mptWkb"));
+ gisFunctions.add(new GisFunction("ST_MultiPointFromWKB", 5, 7, 6, 0, 0, 0, "mptWkb"));
+ gisFunctions.add(new GisFunction("ST_MPolyFromWKB", 5, 7, 6, 0, 0, 0, "mplWkb"));
+ gisFunctions.add(new GisFunction("ST_MultiPolygonFromWKB", 5, 7, 6, 0, 0, 0, "mplWkb"));
+ gisFunctions.add(new GisFunction("ST_PointFromWKB", 5, 6, 1, 0, 0, 0, "ptWkb"));
+ gisFunctions.add(new GisFunction("ST_PolyFromWKB", 5, 6, 1, 0, 0, 0, "plWkb"));
+ gisFunctions.add(new GisFunction("ST_PolygonFromWKB", 5, 6, 1, 0, 0, 0, "plWkb"));
+ // MySQL-Specific Functions That Create Geometry Values
+ gisFunctions.add(new GisFunction("GeometryCollection", 5, 5, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("LineString", 5, 5, 1, 0, 0, 0, "pt1", "pt2"));
+ gisFunctions.add(new GisFunction("MultiLineString", 5, 5, 1, 0, 0, 0, "ls1", "ls2"));
+ gisFunctions.add(new GisFunction("MultiPoint", 5, 5, 1, 0, 0, 0, "pt1", "pt2"));
+ gisFunctions.add(new GisFunction("MultiPolygon", 5, 5, 1, 0, 0, 0, "pl1", "pl2"));
+ gisFunctions.add(new GisFunction("Point", 5, 5, 1, 0, 0, 0, "4", "6"));
+ gisFunctions.add(new GisFunction("Polygon", 5, 5, 1, 0, 0, 0, "ls1", "ls2"));
+ // Geometry Format Conversion Functions
+ gisFunctions.add(new GisFunction("AsBinary", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("AsWKB", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("AsText", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("AsWKT", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("ST_AsBinary", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_AsWKB", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_AsText", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_AsWKT", 5, 6, 1, 0, 0, 0, "g"));
+ // General Geometry Property Functions
+ gisFunctions.add(new GisFunction("Dimension", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("Envelope", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("GeometryType", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("IsEmpty", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("IsSimple", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("SRID", 5, 5, 1, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("ST_Dimension", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_Envelope", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_GeometryType", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_IsEmpty", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_IsSimple", 5, 6, 1, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_SRID", 5, 6, 1, 0, 0, 0, "g"));
+ // Point Property Functions
+ gisFunctions.add(new GisFunction("X", 5, 5, 1, 5, 7, 6, "pt"));
+ gisFunctions.add(new GisFunction("Y", 5, 5, 1, 5, 7, 6, "pt"));
+ gisFunctions.add(new GisFunction("ST_X", 5, 6, 1, 0, 0, 0, "pt"));
+ gisFunctions.add(new GisFunction("ST_Y", 5, 6, 1, 0, 0, 0, "pt"));
+ // LineString and MultiLineString Property Functions
+ gisFunctions.add(new GisFunction("EndPoint", 5, 5, 1, 5, 7, 6, "ls"));
+ gisFunctions.add(new GisFunction("GLength", 5, 5, 1, 5, 7, 6, "ls"));
+ gisFunctions.add(new GisFunction("IsClosed", 5, 5, 1, 5, 7, 6, "ls"));
+ gisFunctions.add(new GisFunction("NumPoints", 5, 5, 1, 5, 7, 6, "ls"));
+ gisFunctions.add(new GisFunction("PointN", 5, 5, 1, 5, 7, 6, "ls", "2"));
+ gisFunctions.add(new GisFunction("StartPoint", 5, 5, 1, 5, 7, 6, "ls"));
+ gisFunctions.add(new GisFunction("ST_EndPoint", 5, 6, 1, 0, 0, 0, "ls"));
+ gisFunctions.add(new GisFunction("ST_IsClosed", 5, 6, 1, 0, 0, 0, "ls"));
+ gisFunctions.add(new GisFunction("ST_Length", 5, 7, 6, 0, 0, 0, "ls"));
+ gisFunctions.add(new GisFunction("ST_NumPoints", 5, 6, 1, 0, 0, 0, "ls"));
+ gisFunctions.add(new GisFunction("ST_PointN", 5, 6, 1, 0, 0, 0, "ls", "2"));
+ gisFunctions.add(new GisFunction("ST_StartPoint", 5, 6, 1, 0, 0, 0, "ls"));
+ // Polygon and MultiPolygon Property Functions
+ gisFunctions.add(new GisFunction("Area", 5, 5, 1, 5, 7, 6, "pl"));
+ gisFunctions.add(new GisFunction("Centroid", 5, 5, 1, 5, 7, 6, "mpl"));
+ gisFunctions.add(new GisFunction("ExteriorRing", 5, 5, 1, 5, 7, 6, "pl"));
+ gisFunctions.add(new GisFunction("InteriorRingN", 5, 5, 1, 5, 7, 6, "pl", "1"));
+ gisFunctions.add(new GisFunction("NumInteriorRings", 5, 5, 1, 5, 7, 6, "pl"));
+ gisFunctions.add(new GisFunction("ST_Area", 5, 6, 1, 0, 0, 0, "pl"));
+ gisFunctions.add(new GisFunction("ST_Centroid", 5, 6, 1, 0, 0, 0, "mpl"));
+ gisFunctions.add(new GisFunction("ST_ExteriorRing", 5, 6, 1, 0, 0, 0, "pl"));
+ gisFunctions.add(new GisFunction("ST_InteriorRingN", 5, 6, 1, 0, 0, 0, "pl", "1"));
+ gisFunctions.add(new GisFunction("ST_NumInteriorRing", 5, 7, 8, 0, 0, 0, "pl"));
+ gisFunctions.add(new GisFunction("ST_NumInteriorRings ", 5, 6, 1, 0, 0, 0, "pl"));
+ // GeometryCollection Property Functions
+ gisFunctions.add(new GisFunction("GeometryN", 5, 5, 1, 5, 7, 6, "gc", "2"));
+ gisFunctions.add(new GisFunction("NumGeometries", 5, 5, 1, 5, 7, 6, "gc"));
+ gisFunctions.add(new GisFunction("ST_GeometryN", 5, 6, 1, 0, 0, 0, "gc", "2"));
+ gisFunctions.add(new GisFunction("ST_NumGeometries", 5, 6, 1, 0, 0, 0, "gc"));
+ // Spatial Operator Functions
+ gisFunctions.add(new GisFunction("Buffer", 5, 6, 1, 5, 7, 6, "g", "1"));
+ gisFunctions.add(new GisFunction("ConvexHull", 5, 7, 5, 5, 7, 6, "g"));
+ gisFunctions.add(new GisFunction("ST_Buffer", 5, 6, 1, 0, 0, 0, "g", "1"));
+ gisFunctions.add(new GisFunction("ST_Buffer_Strategy", 5, 7, 7, 0, 0, 0, "'point_circle'", "2"));
+ gisFunctions.add(new GisFunction("ST_ConvexHull", 5, 7, 5, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_Difference", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Intersection", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_SymDifference", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Union", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ // Spatial Relation Functions That Use Object Shapes
+ gisFunctions.add(new GisFunction("Crosses", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("Distance", 5, 7, 5, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("Touches", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Contains", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Crosses", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Disjoint", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Distance", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Equals", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Intersects", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Overlaps", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Touches", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("ST_Within", 5, 6, 1, 0, 0, 0, "g1", "g2"));
+ // Spatial Relation Functions That Use Minimum Bounding Rectangles (MBRs)
+ gisFunctions.add(new GisFunction("Contains", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("Disjoint", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("Equals", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("Intersects", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("Overlaps", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("Within", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBRContains", 5, 5, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBRCoveredBy", 5, 7, 6, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBRCovers", 5, 7, 6, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBRDisjoint", 5, 5, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBREqual", 5, 5, 1, 5, 7, 6, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBREquals", 5, 7, 6, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBRIntersects", 5, 5, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBROverlaps", 5, 5, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBRTouches", 5, 5, 1, 0, 0, 0, "g1", "g2"));
+ gisFunctions.add(new GisFunction("MBRWithin", 5, 5, 1, 0, 0, 0, "g1", "g2"));
+ // Spatial Geohash Functions
+ gisFunctions.add(new GisFunction("ST_GeoHash", 5, 7, 5, 0, 0, 0, "pt", "20"));
+ gisFunctions.add(new GisFunction("ST_LatFromGeoHash", 5, 7, 5, 0, 0, 0, "gh"));
+ gisFunctions.add(new GisFunction("ST_LongFromGeoHash", 5, 7, 5, 0, 0, 0, "gh"));
+ gisFunctions.add(new GisFunction("ST_PointFromGeoHash", 5, 7, 5, 0, 0, 0, "gh", "0"));
+ // Spatial GeoJSON Functions
+ gisFunctions.add(new GisFunction("ST_AsGeoJSON", 5, 7, 5, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_GeomFromGeoJSON", 5, 7, 5, 0, 0, 0, "js"));
+ // Spatial Convenience Functions
+ gisFunctions.add(new GisFunction("ST_Distance_Sphere", 5, 7, 6, 0, 0, 0, "pt1", "pt2"));
+ gisFunctions.add(new GisFunction("ST_IsValid", 5, 7, 6, 0, 0, 0, "g"));
+ gisFunctions.add(new GisFunction("ST_MakeEnvelope", 5, 7, 6, 0, 0, 0, "pt1", "pt2"));
+ gisFunctions.add(new GisFunction("ST_Simplify", 5, 7, 6, 0, 0, 0, "g", "1"));
+ gisFunctions.add(new GisFunction("ST_Validate", 5, 7, 6, 0, 0, 0, "g"));
+
+ for (GisFunction gf : gisFunctions) {
+ if (versionMeetsMinimum(gf.low_version_maj, gf.low_version_min, gf.low_version_sub)
+ && (gf.hi_version_maj == 0 || !versionMeetsMinimum(gf.hi_version_maj, gf.hi_version_min, gf.hi_version_sub))) {
+ final StringBuilder sql = new StringBuilder("SELECT ");
+ sql.append(gf.function).append("(");
+ String sep = "";
+ for (String arg : gf.args) {
+ sql.append(sep);
+ sep = ", ";
+ if (args.containsKey(arg)) {
+ sql.append(args.get(arg));
+ } else {
+ sql.append(arg);
+ }
+ }
+ sql.append(")");
+
+ this.rs = this.stmt.executeQuery(sql.toString());
+ assertTrue("Query should return one row.", this.rs.next());
+ assertFalse("Query should return exactly one row.", this.rs.next());
+
+ this.pstmt = this.conn.prepareStatement(sql.toString());
+ this.rs = this.pstmt.executeQuery();
+ assertTrue("Query should return one row.", this.rs.next());
+ assertFalse("Query should return exactly one row.", this.rs.next());
+ }
+ }
+ }
+
+ /**
+ * WL#8252 - GCS Replication: Plugin [SERVER CHANGES]
+ *
+ * Test syntax for GCS Replication commands:
+ * - START GROUP_REPLICATION
+ * - STOP GROUP_REPLICATION
+ */
+ public void testGcsReplicationCmds() throws Exception {
+ if (!versionMeetsMinimum(5, 7, 6)) {
+ return;
+ }
+ String expectedErrMsg = "The server is not configured properly to be an active member of the group\\. Please see more details on error log\\.";
+ final Statement testStmt = this.stmt;
+ assertThrows(SQLException.class, expectedErrMsg, new Callable<Void>() {
+ public Void call() throws Exception {
+ testStmt.execute("START GROUP_REPLICATION");
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, expectedErrMsg, new Callable<Void>() {
+ public Void call() throws Exception {
+ testStmt.execute("STOP GROUP_REPLICATION");
+ return null;
+ }
+ });
+
+ Connection spsConn = getConnectionWithProps("useServerPrepStmts=true");
+ for (Connection testConn : new Connection[] { this.conn, spsConn }) {
+ final PreparedStatement testPstmt1 = testConn.prepareStatement("START GROUP_REPLICATION");
+ assertThrows(SQLException.class, expectedErrMsg, new Callable<Void>() {
+ public Void call() throws Exception {
+ testPstmt1.execute();
+ return null;
+ }
+ });
+ final PreparedStatement testPstmt2 = testConn.prepareStatement("STOP GROUP_REPLICATION");
+ assertThrows(SQLException.class, expectedErrMsg, new Callable<Void>() {
+ public Void call() throws Exception {
+ testPstmt2.execute();
+ return null;
+ }
+ });
+ }
+ spsConn.close();
+ }
+
+ /**
+ * WL#6054 - Temporarily disablement of users
+ *
+ * Test user account locking syntax:
+ *
+ * CREATE|ALTER USER (...)
+ * - lock_option: { ACCOUNT LOCK | ACCOUNT UNLOCK }
+ */
+ public void testUserAccountLocking() throws Exception {
+ if (!versionMeetsMinimum(5, 7, 6)) {
+ return;
+ }
+
+ final String user = "testAccLck";
+ final String pwd = "testAccLck";
+ final Properties props = new Properties();
+ props.setProperty("user", user);
+ props.setProperty("password", pwd);
+
+ for (String accLock : new String[] { "/* default */", "ACCOUNT UNLOCK", "ACCOUNT LOCK" }) {
+ createUser("'" + user + "'@'%'", "IDENTIFIED BY '" + pwd + "' " + accLock);
+ this.stmt.execute("GRANT SELECT ON *.* TO '" + user + "'@'%'");
+
+ if (accLock.equals("ACCOUNT LOCK")) {
+ assertThrows("Test case: " + accLock + ",", SQLException.class, "Access denied for user '" + user + "'@'.*'\\. Account is locked\\.",
+ new Callable<Void>() {
+ public Void call() throws Exception {
+ getConnectionWithProps(props);
+ return null;
+ }
+ });
+ this.stmt.execute("ALTER USER '" + user + "'@'%' ACCOUNT UNLOCK");
+ }
+
+ final Connection testConn1 = getConnectionWithProps(props);
+ assertTrue("Test case: " + accLock + ",", testConn1.createStatement().executeQuery("SELECT 1").next());
+
+ this.stmt.execute("ALTER USER '" + user + "'@'%' ACCOUNT LOCK");
+ assertTrue("Test case: " + accLock + ",", testConn1.createStatement().executeQuery("SELECT 1").next()); // Previous authentication still valid.
+
+ assertThrows("Test case: " + accLock + ",", SQLException.class, "Access denied for user '" + user + "'@'.*'\\. Account is locked\\.",
+ new Callable<Void>() {
+ public Void call() throws Exception {
+ ((MySQLConnection) testConn1).changeUser(user, pwd);
+ return null;
+ }
+ });
+ assertFalse("Test case: " + accLock + ",", testConn1.isClosed());
+ assertThrows("Test case: " + accLock + ",", SQLException.class, "(?s)Communications link failure.*", new Callable<Void>() {
+ public Void call() throws Exception {
+ testConn1.createStatement().executeQuery("SELECT 1");
+ return null;
+ }
+ });
+ assertTrue("Test case: " + accLock + ",", testConn1.isClosed());
+
+ this.stmt.execute("ALTER USER '" + user + "'@'%' ACCOUNT UNLOCK");
+ Connection testConn2 = getConnectionWithProps(props);
+ assertTrue("Test case: " + accLock + ",", testConn2.createStatement().executeQuery("SELECT 1").next());
+ testConn2.close();
+
+ dropUser("'" + user + "'@'%'");
+ }
+ }
+
+ /**
+ * WL#7131 - Add timestamp in mysql.user on the last time the password was changed
+ *
+ * Test user account password expiration syntax:
+ *
+ * CREATE|ALTER USER (...)
+ * - password_option: { PASSWORD EXPIRE | PASSWORD EXPIRE DEFAULT | PASSWORD EXPIRE NEVER | PASSWORD EXPIRE INTERVAL N DAY }
+ */
+ public void testUserAccountPwdExpiration() throws Exception {
+ if (!versionMeetsMinimum(5, 7, 6)) {
+ return;
+ }
+
+ final String user = "testAccPwdExp";
+ final String pwd = "testAccPwdExp";
+ final Properties props = new Properties();
+ props.setProperty("user", user);
+ props.setProperty("password", pwd);
+
+ // CREATE USER syntax.
+ for (String accPwdExp : new String[] { "/* default */", "PASSWORD EXPIRE", "PASSWORD EXPIRE DEFAULT", "PASSWORD EXPIRE NEVER",
+ "PASSWORD EXPIRE INTERVAL 365 DAY" }) {
+ createUser("'" + user + "'@'%'", "IDENTIFIED BY '" + pwd + "' " + accPwdExp);
+ this.stmt.execute("GRANT SELECT ON *.* TO '" + user + "'@'%'");
+
+ if (accPwdExp.equals("PASSWORD EXPIRE")) {
+ assertThrows(SQLException.class, "Your password has expired\\. To log in you must change it using a client that supports expired passwords\\.",
+ new Callable<Void>() {
+ public Void call() throws Exception {
+ getConnectionWithProps(props);
+ return null;
+ }
+ });
+ } else {
+ Connection testConn = getConnectionWithProps(props);
+ assertTrue("Test case: " + accPwdExp + ",", testConn.createStatement().executeQuery("SELECT 1").next());
+ testConn.close();
+ }
+
+ dropUser("'" + user + "'@'%'");
+ }
+
+ // ALTER USER syntax.
+ for (String accPwdExp : new String[] { "PASSWORD EXPIRE", "PASSWORD EXPIRE DEFAULT", "PASSWORD EXPIRE NEVER", "PASSWORD EXPIRE INTERVAL 365 DAY" }) {
+ createUser("'" + user + "'@'%'", "IDENTIFIED BY '" + pwd + "'");
+ this.stmt.execute("GRANT SELECT ON *.* TO '" + user + "'@'%'");
+
+ final Connection testConn = getConnectionWithProps(props);
+ assertTrue("Test case: " + accPwdExp + ",", testConn.createStatement().executeQuery("SELECT 1").next());
+
+ this.stmt.execute("ALTER USER '" + user + "'@'%' " + accPwdExp);
+ assertTrue("Test case: " + accPwdExp + ",", testConn.createStatement().executeQuery("SELECT 1").next());
+
+ if (accPwdExp.equals("PASSWORD EXPIRE")) {
+ assertThrows(SQLException.class, "Your password has expired\\. To log in you must change it using a client that supports expired passwords\\.",
+ new Callable<Void>() {
+ public Void call() throws Exception {
+ ((MySQLConnection) testConn).changeUser(user, pwd);
+ return null;
+ }
+ });
+ } else {
+ ((MySQLConnection) testConn).changeUser(user, pwd);
+ assertTrue("Test case: " + accPwdExp + ",", testConn.createStatement().executeQuery("SELECT 1").next());
+ }
+
+ testConn.close();
+ dropUser("'" + user + "'@'%'");
+ }
+ }
+
+ /**
+ * WL#8548 - InnoDB: Transparent data encryption.
+ * WL#8821 - Innodb tablespace encryption key rotation SQL commands.
+ *
+ * Test new syntax:
+ * - CREATE|ALTER TABLE (...) ENCRYPTION [=] {'Y' | 'N'}
+ * - ALTER INSTANCE ROTATE INNODB MASTER KEY
+ */
+ public void testInnodbTablespaceEncryption() throws Exception {
+ if (!versionMeetsMinimum(5, 7, 11)) {
+ return;
+ }
+
+ boolean keyringPluginIsActive = false;
+ this.rs = this.stmt.executeQuery("SELECT (PLUGIN_STATUS='ACTIVE') AS `TRUE` FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring_file'");
+ if (this.rs.next()) {
+ keyringPluginIsActive = this.rs.getBoolean(1);
+ }
+
+ if (keyringPluginIsActive) {
+ createTable("testInnodbTablespaceEncryption", "(id INT, txt VARCHAR(100)) ENCRYPTION='y'");
+
+ this.stmt.executeUpdate("INSERT INTO testInnodbTablespaceEncryption VALUES (123, 'this is a test')");
+ this.rs = this.stmt.executeQuery("SELECT * FROM testInnodbTablespaceEncryption");
+ assertTrue(this.rs.next());
+ assertEquals(123, this.rs.getInt(1));
+ assertEquals("this is a test", this.rs.getString(2));
+ assertFalse(this.rs.next());
+
+ this.stmt.execute("ALTER INSTANCE ROTATE INNODB MASTER KEY");
+ this.rs = this.stmt.executeQuery("SELECT * FROM testInnodbTablespaceEncryption");
+ assertTrue(this.rs.next());
+ assertEquals(123, this.rs.getInt(1));
+ assertEquals("this is a test", this.rs.getString(2));
+ assertFalse(this.rs.next());
+
+ this.stmt.execute("ALTER TABLE testInnodbTablespaceEncryption ENCRYPTION='n'");
+ this.rs = this.stmt.executeQuery("SELECT * FROM testInnodbTablespaceEncryption");
+ assertTrue(this.rs.next());
+ assertEquals(123, this.rs.getInt(1));
+ assertEquals("this is a test", this.rs.getString(2));
+ assertFalse(this.rs.next());
+
+ } else { // Syntax can still be tested by with different outcome.
+ System.out.println("Although not required it is recommended that the 'keyring_file' plugin is properly installed and configured to run this test.");
+
+ final Statement testStmt = this.conn.createStatement();
+ assertThrows(SQLException.class, "Can't find master key from keyring, please check keyring plugin is loaded.", new Callable<Void>() {
+ public Void call() throws Exception {
+ testStmt.execute("CREATE TABLE testInnodbTablespaceEncryption (id INT) ENCRYPTION='y'");
+ testStmt.execute("DROP TABLE testInnodbTablespaceEncryption");
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Can't find master key from keyring, please check keyring plugin is loaded.", new Callable<Void>() {
+ public Void call() throws Exception {
+ testStmt.execute("ALTER INSTANCE ROTATE INNODB MASTER KEY");
+ return null;
+ }
+ });
+ }
+ }
}
diff --git a/src/testsuite/regression/UtilsRegressionTest.java b/src/testsuite/regression/UtilsRegressionTest.java
index 5880bc9..4480d10 100644
--- a/src/testsuite/regression/UtilsRegressionTest.java
+++ b/src/testsuite/regression/UtilsRegressionTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -649,14 +649,14 @@ public class UtilsRegressionTest extends BaseTestCase {
ex = SQLError.createSQLException("ORIGINAL_EXCEPTION", "0", new Exception("ORIGINAL_CAUSE"), new ExceptionInterceptor() {
boolean alreadyIntercepted = false;
- public void init(Connection conn, Properties props) throws SQLException {
+ public void init(Connection con, Properties props) throws SQLException {
this.alreadyIntercepted = false;
}
public void destroy() {
}
- public SQLException interceptException(SQLException sqlEx, Connection conn) {
+ public SQLException interceptException(SQLException sqlEx, Connection con) {
assertFalse(this.alreadyIntercepted);
this.alreadyIntercepted = true;
@@ -673,14 +673,14 @@ public class UtilsRegressionTest extends BaseTestCase {
ex = SQLError.createSQLException("ORIGINAL_EXCEPTION", "0", new Exception("ORIGINAL_CAUSE"), new ExceptionInterceptor() {
boolean alreadyIntercepted = false;
- public void init(Connection conn, Properties props) throws SQLException {
+ public void init(Connection con, Properties props) throws SQLException {
this.alreadyIntercepted = false;
}
public void destroy() {
}
- public SQLException interceptException(SQLException sqlEx, Connection conn) {
+ public SQLException interceptException(SQLException sqlEx, Connection con) {
assertFalse(this.alreadyIntercepted);
this.alreadyIntercepted = true;
diff --git a/src/testsuite/regression/jdbc4/ConnectionRegressionTest.java b/src/testsuite/regression/jdbc4/ConnectionRegressionTest.java
index c2321b0..db4e844 100644
--- a/src/testsuite/regression/jdbc4/ConnectionRegressionTest.java
+++ b/src/testsuite/regression/jdbc4/ConnectionRegressionTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -261,8 +261,7 @@ public class ConnectionRegressionTest extends BaseTestCase {
}
/**
- *
- * @throws Exception
+ * Tests fix for Bug#56122 - JDBC4 functionality failure when using replication connections.
*/
public void testBug56122() throws Exception {
for (final Connection testConn : new Connection[] { this.conn, getFailoverConnection(), getLoadBalancedConnection(),
diff --git a/src/testsuite/regression/jdbc42/ConnectionRegressionTest.java b/src/testsuite/regression/jdbc42/ConnectionRegressionTest.java
new file mode 100644
index 0000000..2a0950e
--- /dev/null
+++ b/src/testsuite/regression/jdbc42/ConnectionRegressionTest.java
@@ -0,0 +1,93 @@
+/*
+ Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+
+ The MySQL Connector/J is licensed under the terms of the GPLv2
+ <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, 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 FOSS License Exception
+ <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+
+ 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 testsuite.regression.jdbc42;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import com.mysql.jdbc.ConnectionImpl;
+import com.mysql.jdbc.MysqlIO;
+import com.mysql.jdbc.SQLError;
+
+import testsuite.BaseTestCase;
+
+public class ConnectionRegressionTest extends BaseTestCase {
+
+ public ConnectionRegressionTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Tests fix for Bug#75615 - Incorrect implementation of Connection.setNetworkTimeout().
+ *
+ * Note: this test exploits a non deterministic race condition. Usually the failure was observed under 10 consecutive executions, as such the siginficant
+ * part of the test is run up to 25 times.
+ */
+ private Future<?> testBug75615Future = null;
+
+ public void testBug75615() throws Exception {
+ // Main use case: although this could cause an exception due to a race condition in MysqlIO.mysqlConnection it is silently swallowed within the running
+ // thread.
+ final Connection testConn1 = getConnectionWithProps("");
+ testConn1.setNetworkTimeout(Executors.newSingleThreadExecutor(), 1000);
+ testConn1.close();
+
+ // Main use case simulation: this simulates the above by capturing an eventual exeption in the main thread. This is where this test would actually fail.
+ // This part is repeated several times to increase the chance of hitting the reported bug.
+ for (int i = 0; i < 25; i++) {
+ final ExecutorService execService = Executors.newSingleThreadExecutor();
+ final Connection testConn2 = getConnectionWithProps("");
+ testConn2.setNetworkTimeout(new Executor() {
+ public void execute(Runnable command) {
+ // Attach the future to the parent object so that it can track the exception in the main thread.
+ ConnectionRegressionTest.this.testBug75615Future = execService.submit(command);
+ }
+ }, 1000);
+ testConn2.close();
+ try {
+ this.testBug75615Future.get();
+ } catch (ExecutionException e) {
+ e.getCause().printStackTrace();
+ fail("Exception thrown in the thread that was setting the network timeout: " + e.getCause());
+ }
+ execService.shutdownNow();
+ }
+
+ // Test the expected exception on null executor.
+ assertThrows(SQLException.class, "Executor can not be null", new Callable<Void>() {
+ public Void call() throws Exception {
+ Connection testConn = getConnectionWithProps("");
+ testConn.setNetworkTimeout(null, 1000);
+ testConn.close();
+ return null;
+ }
+ });
+ }
+}
diff --git a/src/testsuite/simple/CharsetTest.java b/src/testsuite/simple/CharsetTest.java
index 5a2cc3e..77a85e4 100644
--- a/src/testsuite/simple/CharsetTest.java
+++ b/src/testsuite/simple/CharsetTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -424,6 +424,14 @@ public class CharsetTest extends BaseTestCase {
return true;
}
+ public void testStaticCharsetMappingConsistency() {
+ for (int i = 1; i < CharsetMapping.MAP_SIZE; i++) {
+ assertNotNull("Assertion failure: No mapping from charset index " + i + " to a mysql collation",
+ CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[i]);
+ assertNotNull("Assertion failure: No mapping from charset index " + i + " to a Java character set", CharsetMapping.COLLATION_INDEX_TO_CHARSET[i]);
+ }
+ }
+
/**
* Prints static mappings for analysis.
*
diff --git a/src/testsuite/simple/ResultSetTest.java b/src/testsuite/simple/ResultSetTest.java
index 6c73ca4..6146cdb 100644
--- a/src/testsuite/simple/ResultSetTest.java
+++ b/src/testsuite/simple/ResultSetTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -63,9 +63,7 @@ public class ResultSetTest extends BaseTestCase {
// build map of charsets supported by server
Connection c = getConnectionWithProps("detectCustomCollations=true");
Map<String, Integer> charsetsMap = new HashMap<String, Integer>();
- Iterator<Integer> collationIndexes = ((ConnectionImpl) c).indexToMysqlCharset.keySet().iterator();
- while (collationIndexes.hasNext()) {
- Integer index = collationIndexes.next();
+ for (int index = 1; index < CharsetMapping.MAP_SIZE; index++) {
String charsetName = null;
if (((ConnectionImpl) c).indexToCustomMysqlCharset != null) {
charsetName = ((ConnectionImpl) c).indexToCustomMysqlCharset.get(index);
diff --git a/src/testsuite/simple/UtilsTest.java b/src/testsuite/simple/UtilsTest.java
index f0eaccb..ea153eb 100644
--- a/src/testsuite/simple/UtilsTest.java
+++ b/src/testsuite/simple/UtilsTest.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
@@ -32,6 +32,7 @@ import java.util.List;
import com.mysql.jdbc.ConnectionImpl;
import com.mysql.jdbc.ConnectionProperties;
+import com.mysql.jdbc.MultiHostConnectionProxy;
import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.PreparedStatement;
import com.mysql.jdbc.ResultSetImpl;
@@ -132,4 +133,12 @@ public class UtilsTest extends BaseTestCase {
assertTrue(ifacesList.contains(clazz));
}
}
+
+ /**
+ * Tests Util.getPackageName()
+ */
+ public void testGetPackageName() {
+ assertEquals(MultiHostConnectionProxy.class.getPackage().getName(), Util.getPackageName(MultiHostConnectionProxy.class));
+ assertEquals(MySQLConnection.class.getPackage().getName(), Util.getPackageName(this.conn.getClass().getInterfaces()[0]));
+ }
}
\ No newline at end of file
Reply to: