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

Bug#857128: marked as done (unblock: mysql-connector-java/5.1.41-1)



Your message dated Thu, 16 Mar 2017 08:18:23 +0000
with message-id <E1coQc3-0003p0-Pn@respighi.debian.org>
and subject line unblock mysql-connector-java
has caused the Debian Bug report #857128,
regarding unblock: mysql-connector-java/5.1.41-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
857128: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=857128
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
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

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply to: