[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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=&quot;[1.0.1, 2.0.0)&quot;;resolution:=optional" />
-        <property name="crypto-imports" value="javax.net,javax.net.ssl;version=&quot;[1.0.1, 2.0.0)&quot;;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=&quot;[0.9.1.2, 1.0.0)&quot;;resolution:=optional,org.jboss.resource.adapter.jdbc;resolution:=optional,org.jboss.resource.adapter.jdbc.vendor;resolution:=optional" />
+                  value="com.mchange.v2.c3p0;version=&quot;[0.9.1.2,1.0.0)&quot;;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=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc.log,javax.naming,javax.net.ssl,javax.xml.transform,org.xml.sax&quot;" />
+                  value="com.mysql.jdbc;version=&quot;${osgid-version}&quot;;uses:=&quot;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&quot;" />
         <property name="jee-exports"
-                  value="com.mysql.jdbc.jdbc2.optional;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc,com.mysql.jdbc.log,javax.naming,javax.sql,javax.transaction.xa&quot;" />
+                  value="com.mysql.jdbc.jdbc2.optional;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc,com.mysql.jdbc.log,javax.sql,javax.naming,javax.naming.spi,javax.transaction.xa&quot;" />
         <property name="logging-exports" value="com.mysql.jdbc.log;version=&quot;${osgid-version}&quot;" />
-        <property name="profiling-exports" value="com.mysql.jdbc.profiler;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc&quot;" />
-        <property name="util-exports" value="com.mysql.jdbc.util;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc.log&quot;" />
+        <property name="profiling-exports" value="com.mysql.jdbc.profiler;version=&quot;${osgid-version}&quot;" />
+        <property name="util-exports" value="com.mysql.jdbc.util;version=&quot;${osgid-version}&quot;" />
         <property name="exceptions-exports" value="com.mysql.jdbc.exceptions;version=&quot;${osgid-version}&quot;" />
-        <property name="jdbc4-exceptions-exports"
-                  value="com.mysql.jdbc.exceptions.jdbc4;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc&quot;" />
-        <property name="fabric-exports"
-                  value="com.mysql.fabric.jdbc;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc&quot;" />
-
-        <property name="interceptors-exports" value="com.mysql.jdbc.interceptors;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc&quot;" />
+        <property name="jdbc4-exceptions-exports" value="com.mysql.jdbc.exceptions.jdbc4;version=&quot;${osgid-version}&quot;" />
+        <property name="interceptors-exports" value="com.mysql.jdbc.interceptors;version=&quot;${osgid-version}&quot;" />
         <property name="integration-exports"
-                  value="com.mysql.jdbc.integration.c3p0;version=&quot;${osgid-version}&quot;,com.mysql.jdbc.integration.jboss;version=&quot;${osgid-version}&quot;" />
+                  value="com.mysql.jdbc.integration.c3p0;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mchange.v2.c3p0&quot;,com.mysql.jdbc.integration.jboss;version=&quot;${osgid-version}&quot;;uses:=&quot;org.jboss.resource.adapter.jdbc,org.jboss.resource.adapter.jdbc.vendor&quot;" />
         <property name="configs-exports" value="com.mysql.jdbc.configs;version=&quot;${osgid-version}&quot;" />
-        <property name="legacy-exports" value="org.gjt.mm.mysql;version=&quot;${osgid-version}&quot;" />
+        <property name="legacy-exports" value="org.gjt.mm.mysql;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc&quot;" />
+        <property name="fabric-exports"
+                  value="com.mysql.fabric;com.mysql.fabric.hibernate;com.mysql.fabric.jdbc;version=&quot;${osgid-version}&quot;;uses:=&quot;com.mysql.jdbc,javax.xml.datatype;org.hibernate;org.hibernate.cfg;org.hibernate.service;org.hibernate.service.jdbc.connections.spi&quot;" />
 
         <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: