diff --git a/CHANGES b/CHANGES
index e53c1a2bb..45cc8c2a1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,99 @@
# Changelog
# https://dev.mysql.com/doc/relnotes/connector-j/8.0/en/
+Version 8.0.28
+
+ - Fix for Bug#99260 (31189960), statement.setQueryTimeout,creates a database connection and does not close.
+
+ - Fix for Bug#103324 (32770013), X DevAPI Collection.replaceOne() missing matching _id check.
+
+ - Fix for Bug#105197 (33461744), Statement.executeQuery() may return non-navigable ResultSet.
+
+ - Fix for Bug#105323 (33507321), README.md contains broken links.
+
+ - Fix for Bug#96900 (30355150), STATEMENT.CANCEL()CREATE A DATABASE CONNECTION BUT DOES NOT CLOSE THE CONNECTION.
+
+ - Fix for Bug#104067 (33054827), No reset autoCommit after unknown issue occurs.
+ Thanks to Tingyu Wei for his contribution.
+
+ - Fix for Bug#85223 (25656020), MYSQLSQLXML SETSTRING CRASH.
+
+ - Fix for Bug#84365 (33425867), INSERT..VALUE with VALUES function lead to a StringIndexOutOfBoundsException.
+
+ - Fix for Bug#105211 (33468860), class java.time.LocalDate cannot be cast to class java.sql.Date.
+
+ - Fix for Bug#101389 (32089018), GETWARNINGS SHOULD CHECK WARNING COUNT BEFORE SENDING SHOW.
+
+ - Fix for Bug#33488091, Remove all references to xdevapi.useAsyncProtocol from properties and code.
+
+ - WL#14805, Remove support for TLS 1.0 and 1.1.
+
+ - WL#14650, Support for MFA (multi factor authentication) authentication.
+
+Version 8.0.27
+
+ - Fix for Bug#103612 (32902019), Incorrectly identified WITH...SELECT as unsafe for read-only connections.
+
+ - Fix for Bug#71929 (18346501), Prefixing query with double comments cancels query DML validation.
+
+ - Fix for Bug#23204652, CURSOR POSITIONING API'S DOESNOT CHECK THE VALIDITY OF RESULTSET.
+
+ - Fix for Bug#28725534, MULTI HOST CONNECTION WOULD BLOCK IN CONNECTION POOLING.
+
+ - Fix for Bug#95139 (29807572), CACHESERVERCONFIGURATION APPEARS TO THWART CHARSET DETECTION.
+
+ - Fix for Bug#104641 (33237255), DatabaseMetaData.getImportedKeys can return duplicated foreign keys.
+
+ - Fix for Bug#33185116, Have method ResultSet.getBoolean() supporting conversion of 'T' and 'F' in a VARCHAR to True/False (boolean).
+
+ - Fix for Bug#31117686, PROTOCOL ALLOWLIST NOT COMPATIBLE WITH IBM JAVA.
+
+ - Fix for Bug#104559 (33232419), ResultSet.getObject(i, java.util.Date.class) throws NPE when the value is null.
+
+ - WL#14707, Support OCI IAM authentication.
+
+ - WL#14660, Testsuite with support for single MySQL server instance.
+
+ - Fix for Bug#103878 (32954449), CONNECTOR/J 8 : QUERY WITH 'SHOW XXX' WILL GET EXCEPTION WHEN USE CURSOR.
+
+ - Fix for Bug#103796 (32922715), CONNECTOR/J 8 STMT SETQUERYTIMEOUT CAN NOT WORK.
+ Thanks to Hong Wang for his contribution.
+
+ - Fix for Bug#104170 (33064455), CONTRIBUTION: CLIENTPREPAREDSTMT: LEAVE CALENDAR UNTOUCHED.
+ Thanks to Björn Michael for his contribution.
+
+ - Fix for Bug#95564 (29894324), createDatabaseIfNotExist is not working for databases with hyphen in name.
+ Thanks to Lukasz Sanek for his contribution.
+
+Version 8.0.26
+
+ - Fix for Bug#32954396, EXECUTEQUERY HANGS WITH USECURSORFETCH=TRUE & SETFETCHSIZE.
+
+ - Fix for Bug#102372 (32459408), v8.0.23 unusable in OSGi.
+
+ - Fix for Bug#25554464, CONNECT FAILS WITH NPE WHEN THE SERVER STARTED WITH CUSTOM COLLATION.
+
+ - Fix for Bug#100606 (31818423), UNECESARY CALL TO "SET NAMES 'UTF8' COLLATE 'UTF8_GENERAL_CI'".
+ Thanks to Marc Fletcher for his contribution.
+
+ - Fix for Bug#102404 (32435618), CONTRIBUTION: ADD TRACK SESSION STATE CHANGE.
+ Thanks to William Lee for his contribution.
+
+ - Fix for Bug#95280 (29757140), DATABASEMETADATA.GETIMPORTEDKEYS RETURNS DOUBLE THE ROWS.
+ Thanks to Miron Balcerzak for his contribution.
+
+ - Fix for Bug#97269 (30438500), POSSIBLE BUG IN COM.MYSQL.CJ.XDEVAPI.STREAMINGDOCRESULTBUILDER.
+
+ - Fix for Bug#103303 (32766143), JAVA.LANG.CLASSCASTEXCEPTION WHEN INSERTING BLOB WITH SERVER PREPARED STATEMENT.
+
+ - WL#14205, Support query attributes.
+
+ - WL#14411, Support for authentication_kerberos_client authentication plugin.
+
+ - WL#14559, Deprecate TLS 1.0 and 1.1.
+
+ - WL#14391, Migrate QA tests to main repo.
+
Version 8.0.25
- This release contains no functional changes and is published to align the version number with the MySQL Server 8.0.25 release.
diff --git a/LICENSE b/LICENSE
index e66b83f4a..83e60a354 100644
--- a/LICENSE
+++ b/LICENSE
@@ -10,7 +10,7 @@ Introduction
third-party software which may be included in this distribution of
MySQL Connector/J 8.0.
- Last updated: April 2021
+ Last updated: September 2021
Licensing Information
@@ -428,6 +428,7 @@ The Universal FOSS Exception, Version 1.0
Software with Other FOSS, and the constants, function signatures, data
structures and other invocation methods used to run or interact with
each of them (as to each, such software's "Interfaces"):
+
i. The Software's Interfaces may, to the extent permitted by the
license of the Other FOSS, be copied into, used and distributed in
the Other FOSS in order to enable interoperability, without
@@ -437,6 +438,7 @@ The Universal FOSS Exception, Version 1.0
including without limitation as used in the Other FOSS (which upon
any such use also then contains a portion of the Software under the
Software License).
+
ii. The Other FOSS's Interfaces may, to the extent permitted by the
license of the Other FOSS, be copied into, used and distributed in
the Software in order to enable interoperability, without requiring
@@ -444,6 +446,7 @@ The Universal FOSS Exception, Version 1.0
License or otherwise altering their original terms, if this does
not require any portion of the Software other than such Interfaces
to be licensed under the terms other than the Software License.
+
iii. If only Interfaces and no other code is copied between the
Software and the Other FOSS in either direction, the use and/or
distribution of the Software with the Other FOSS shall not be
@@ -479,6 +482,7 @@ c3p0 JDBC Library
The MySQL Connector/J implements interfaces that are included in c3p0,
although no part of c3p0 is included or distributed with MySQL.
+
Copyright (C) 2019 Machinery For Change, Inc.
* This library is free software; you can redistribute it and/or modify
@@ -1121,6 +1125,65 @@ Apache License Version 2.0, January 2004
+ ======================================================================
+ ======================================================================
+
+Oracle OCI SDK for Java
+
+ Oracle OCI SDK for Java
+
+Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
+This software is dual-licensed to you under the Universal Permissive License
+(UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl
+or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0.
+You may choose either license.
+____________________________
+The Universal Permissive License (UPL), Version 1.0
+Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+Subject to the condition set forth below, permission is hereby granted to any
+person obtaining a copy of this software, associated documentation and/or
+data (collectively the "Software"), free of charge and under any and all
+copyright rights in the Software, and any and all patent rights owned or
+freely licensable by each licensor hereunder covering either (i) the
+unmodified Software as contributed to or provided by such licensor, or (ii)
+the Larger Works (as defined below), to deal in both
+(a) the Software, and
+(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
+one is included with the Software (each a "Larger Work" to which the Software
+is contributed by such licensors),
+without restriction, including without limitation the rights to copy, create
+derivative works of, display, perform, and distribute the Software and make,
+use, sell, offer for sale, import, export, have made, and have sold the
+Software and the Larger Work(s), and to sublicense the foregoing rights on
+either these or other terms.
+This license is subject to the following condition:
+The above copyright notice and either this complete permission notice or at a
+minimum a reference to the UPL must be included in all copies or substantial
+portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+The Apache Software License, Version 2.0
+Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+Licensed under the Apache License, Version 2.0 (the "License"); You may not
+use this product except in compliance with the License. You may obtain a
+copy of the License at http://www.apache.org/licenses/LICENSE-2.0. A copy of
+the license is also reproduced below. Unless required by applicable law or
+agreed to in writing, software distributed under the License is distributed
+on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+express or implied. See the License for the specific language governing
+permissions and limitations under the License.
+
+Apache License Version 2.0, January 2004
+
+Oracle's use of OCI SDK for Java in MySQL Community Edition is solely under
+the UPL
+
======================================================================
======================================================================
@@ -1161,6 +1224,7 @@ OR OTHER DEALINGS IN THE SOFTWARE.
Unicode Data Files
Unicode Data Files
+
COPYRIGHT AND PERMISSION NOTICE
Copyright (c) 1991-2014 Unicode, Inc. All rights reserved. Distributed under
@@ -1950,6 +2014,7 @@ Written Offer for Source Code
request to the address listed below or by sending an email to Oracle
using the following link:
http://www.oracle.com/goto/opensourcecode/request.
+
Oracle America, Inc.
Attn: Senior Vice President
Development and Engineering Legal
@@ -1957,20 +2022,30 @@ Written Offer for Source Code
Redwood Shores, CA 94065
Your request should include:
+
* The name of the binary for which you are requesting the source code
+
* The name and version number of the Oracle product containing the
binary
+
* The date you received the Oracle product
+
* Your name
+
* Your company name (if applicable)
+
* Your return mailing address and email, and
+
* A telephone number in the event we need to reach you.
+
We may charge you a fee to cover the cost of physical media and
processing.
Your request must be sent
+
a. within three (3) years of the date you received the Oracle product
that included the binary that is the subject of your request, or
+
b. in the case of code licensed under the GPL v3 for as long as Oracle
offers spare parts or customer support for that product model.
diff --git a/README b/README
index 952630f6b..0114ce35c 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Copyright (c) 2000, 2021, Oracle and/or its affiliates.
+Copyright (c) 2000, 2022, Oracle and/or its affiliates.
This is a release of MySQL Connector/J, a JDBC Type 4 driver for MySQL that
also supports the new X DevAPI.
diff --git a/README.md b/README.md
index d41ac09e8..46a3f00b7 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# MySQL Connector/J
-[](https://github.com/mysql/mysql-connector-j/tree/release/8.0/src) [](LICENSE) [](https://search.maven.org/artifact/mysql/mysql-connector-java/8.0.25/jar)
+[](https://github.com/mysql/mysql-connector-j/tree/release/8.0/src) [](LICENSE) [](https://search.maven.org/artifact/mysql/mysql-connector-java/8.0.28/jar)
MySQL provides connectivity for client applications developed in the Java programming language with MySQL Connector/J, a driver that implements the [Java Database Connectivity (JDBC) API](https://www.oracle.com/technetwork/java/javase/jdbc/) and also [MySQL X DevAPI](https://dev.mysql.com/doc/x-devapi-userguide/en/).
@@ -30,7 +30,7 @@ Alternatively, Connector/J can be obtained automatically via [Maven's dependency
mysql
mysql-connector-java
- 8.0.25
+ 8.0.28
```
@@ -53,8 +53,8 @@ There are a few ways to contribute to the Connector/J code. Please refer to the
* [MySQL Connector/J, JDBC and Java forum](https://forums.mysql.com/list.php?39).
* [`#connectors` channel in MySQL Community Slack](https://mysqlcommunity.slack.com/messages/connectors). ([Sign-up](https://lefred.be/mysql-community-on-slack/) required if you do not have an Oracle account.)
* [@MySQL on Twitter](https://twitter.com/MySQL).
-* [MySQL and Java Mailing Lists](https://lists.mysql.com/java).
-* [InsideMySQL.com Connectors Blog](https://insidemysql.com/category/mysql-development/connectors/).
+* [MySQL Blog](https://blogs.oracle.com/mysql/).
+* [MySQL Connectors Blog archive](https://dev.mysql.com/blog-archive/?cat=Connectors%20%2F%20Languages).
* [MySQL Bugs Database](https://bugs.mysql.com/).
For more information about this and other MySQL products, please visit [MySQL Contact & Questions](https://www.mysql.com/about/contact/).
diff --git a/build.xml b/build.xml
index d1b1ab953..c65df5250 100644
--- a/build.xml
+++ b/build.xml
@@ -1,6 +1,6 @@
@@ -1189,7 +1189,7 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
overview="src/main/doc/mysqlx-overview.html"
windowtitle="MySQL Connector/J X DevAPI Reference"
header="<b>MySQL Connector/J X DevAPI Reference<br>v1</b>"
- bottom="<center>Copyright © 2016, 2021, Oracle and/or its affiliates.</center>"
+ bottom="<center>Copyright © 2016, 2022, Oracle and/or its affiliates.</center>"
linkoffline="https://docs.oracle.com/javase/8/docs/api ${com.mysql.cj.docs.jdk8pkg}">
@@ -1236,11 +1236,30 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ depends="-testsuite-jvm-check, compile-testsuite, -init-custom-xslt">
@@ -1283,6 +1302,9 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
+
+
+
@@ -1295,7 +1317,7 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
-
+
@@ -1309,7 +1331,7 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
-
+
@@ -1324,7 +1346,7 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
-
+
@@ -1334,7 +1356,7 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
-
+
@@ -1353,9 +1375,7 @@ See also com.mysql.cj.conf.PropertyDefinitions.SYSP_* variables for other test o
-
+
diff --git a/src/build/java/instrumentation/TranslateExceptions.java b/src/build/java/instrumentation/TranslateExceptions.java
index 6df6eac54..cc94aab8d 100644
--- a/src/build/java/instrumentation/TranslateExceptions.java
+++ b/src/build/java/instrumentation/TranslateExceptions.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -292,7 +292,7 @@ public static void main(String[] args) throws Exception {
/*
* java.sql.PreparedStatement extends java.sql.Statement (java.sql.Statement extends java.sql.Wrapper)
*/
- // com.mysql.cj.jdbc.PreparedStatement extends com.mysql.cj.jdbc.StatementImpl implements java.sql.PreparedStatement
+ // com.mysql.cj.jdbc.ClientPreparedStatement extends com.mysql.cj.jdbc.StatementImpl implements java.sql.PreparedStatement
clazz = pool.get(ClientPreparedStatement.class.getName());
instrumentJdbcMethods(clazz, java.sql.PreparedStatement.class, false, EXCEPTION_INTERCEPTOR_GETTER);
instrumentJdbcMethods(clazz, JdbcStatement.class, true, EXCEPTION_INTERCEPTOR_GETTER);
@@ -318,7 +318,6 @@ public static void main(String[] args) throws Exception {
catchRuntimeException(clazz, clazz.getDeclaredMethod("getParameterBindings", new CtClass[] {}), EXCEPTION_INTERCEPTOR_GETTER);
catchRuntimeException(clazz, clazz.getDeclaredMethod("initializeFromParseInfo", new CtClass[] {}), EXCEPTION_INTERCEPTOR_GETTER);
catchRuntimeException(clazz, clazz.getDeclaredMethod("isNull", new CtClass[] { CtClass.intType }), EXCEPTION_INTERCEPTOR_GETTER);
- catchRuntimeException(clazz, clazz.getDeclaredMethod("isSelectQuery", new CtClass[] {}), EXCEPTION_INTERCEPTOR_GETTER);
catchRuntimeException(clazz, clazz.getDeclaredMethod("prepareBatchedInsertSQL", new CtClass[] { ctJdbcConnection, CtClass.intType }),
EXCEPTION_INTERCEPTOR_GETTER);
catchRuntimeException(clazz,
@@ -328,7 +327,7 @@ public static void main(String[] args) throws Exception {
clazz.writeFile(args[0]);
/*
- * com.mysql.cj.jdbc.ServerPreparedStatement extends PreparedStatement
+ * com.mysql.cj.jdbc.ServerPreparedStatement extends ClientPreparedStatement
*/
clazz = pool.get(ServerPreparedStatement.class.getName());
instrumentJdbcMethods(clazz, java.sql.PreparedStatement.class, false, EXCEPTION_INTERCEPTOR_GETTER);
diff --git a/src/build/misc/debian.in/compat b/src/build/misc/debian.in/compat
index ec635144f..b4de39476 100644
--- a/src/build/misc/debian.in/compat
+++ b/src/build/misc/debian.in/compat
@@ -1 +1 @@
-9
+11
diff --git a/src/build/misc/pom.xml b/src/build/misc/pom.xml
index 0b8b2cf97..6b756545c 100644
--- a/src/build/misc/pom.xml
+++ b/src/build/misc/pom.xml
@@ -1,6 +1,6 @@
Client\n");
+ packetDump.append("\nPacket payload:\n\n");
+ packetDump.append(this.lastHeaderPayload);
+ packetDump.append(PacketPayloadImpl);
+
+ if (bytesToDump == MAX_PACKET_DUMP_LENGTH) {
+ packetDump.append("\nNote: Packet of " + packetLength + " bytes truncated to " + MAX_PACKET_DUMP_LENGTH + " bytes.\n");
+ }
+
+ if ((this.packetDebugBuffer.size() + 1) > this.packetDebugBufferSize.getValue()) {
+ this.packetDebugBuffer.removeFirst();
+ }
+
+ this.packetDebugBuffer.addLast(packetDump);
+
+ return buf;
+ }
+
@Override
public byte getMessageSequence() {
return this.packetReader.getMessageSequence();
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/MultiPacketReader.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/MultiPacketReader.java
index d7ea9440a..c10ed06b7 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/MultiPacketReader.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/MultiPacketReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -54,6 +54,11 @@ public NativePacketHeader readHeader() throws IOException {
return this.packetReader.readHeader();
}
+ @Override
+ public NativePacketHeader probeHeader() throws IOException {
+ return this.packetReader.probeHeader();
+ }
+
@Override
public NativePacketPayload readMessage(Optional reuse, NativePacketHeader header) throws IOException {
@@ -93,6 +98,45 @@ public NativePacketPayload readMessage(Optional reuse, Nati
return buf;
}
+ @Override
+ public NativePacketPayload probeMessage(Optional reuse, NativePacketHeader header) throws IOException {
+
+ int packetLength = header.getMessageSize();
+ NativePacketPayload buf = this.packetReader.probeMessage(reuse, header);
+
+ if (packetLength == NativeConstants.MAX_PACKET_SIZE) { // it's a multi-packet
+
+ buf.setPosition(NativeConstants.MAX_PACKET_SIZE);
+
+ NativePacketPayload multiPacket = null;
+ int multiPacketLength = -1;
+ byte multiPacketSeq = getMessageSequence();
+
+ do {
+ NativePacketHeader hdr = readHeader();
+ multiPacketLength = hdr.getMessageSize();
+
+ if (multiPacket == null) {
+ multiPacket = new NativePacketPayload(multiPacketLength);
+ }
+
+ multiPacketSeq++;
+ if (multiPacketSeq != hdr.getMessageSequence()) {
+ throw new IOException(Messages.getString("PacketReader.10"));
+ }
+
+ this.packetReader.probeMessage(Optional.of(multiPacket), hdr);
+
+ buf.writeBytes(StringLengthDataType.STRING_FIXED, multiPacket.getByteBuffer(), 0, multiPacketLength);
+
+ } while (multiPacketLength == NativeConstants.MAX_PACKET_SIZE);
+
+ buf.setPosition(0);
+ }
+
+ return buf;
+ }
+
@Override
public byte getMessageSequence() {
return this.packetReader.getMessageSequence();
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeAuthenticationProvider.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeAuthenticationProvider.java
index af48c520a..e1b591822 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeAuthenticationProvider.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeAuthenticationProvider.java
@@ -55,7 +55,9 @@
import com.mysql.cj.protocol.a.NativeConstants.IntegerDataType;
import com.mysql.cj.protocol.a.NativeConstants.StringLengthDataType;
import com.mysql.cj.protocol.a.NativeConstants.StringSelfDataType;
+import com.mysql.cj.protocol.a.authentication.AuthenticationKerberosClient;
import com.mysql.cj.protocol.a.authentication.AuthenticationLdapSaslClientPlugin;
+import com.mysql.cj.protocol.a.authentication.AuthenticationOciClient;
import com.mysql.cj.protocol.a.authentication.CachingSha2PasswordPlugin;
import com.mysql.cj.protocol.a.authentication.MysqlClearPasswordPlugin;
import com.mysql.cj.protocol.a.authentication.MysqlNativePasswordPlugin;
@@ -120,8 +122,6 @@ public void init(Protocol prot, PropertySet propSet, Except
* Initialize communications with the MySQL server. Handles logging on, and
* handling initial connection errors.
*
- * @param sessState
- * The session state object. It's intended to be updated from the handshake
* @param user
* user name
* @param pass
@@ -130,7 +130,8 @@ public void init(Protocol prot, PropertySet propSet, Except
* database name
*/
@Override
- public void connect(ServerSession sessState, String user, String pass, String db) {
+ public void connect(String user, String pass, String db) {
+ ServerSession sessState = this.protocol.getServerSession();
this.username = user;
this.password = pass;
this.database = db;
@@ -151,7 +152,6 @@ public void connect(ServerSession sessState, String user, String pass, String db
throw ExceptionFactory.createException(UnableToConnectException.class, "CLIENT_PLUGIN_AUTH is required", getExceptionInterceptor());
}
- sessState.setServerDefaultCollationIndex(capabilities.getServerDefaultCollationIndex()); // read character set (1 byte)
sessState.setStatusFlags(capabilities.getStatusFlags()); // read status flags (2 bytes)
int authPluginDataLength = capabilities.getAuthPluginDataLength();
@@ -164,37 +164,38 @@ public void connect(ServerSession sessState, String user, String pass, String db
this.useConnectWithDb = (this.database != null) && (this.database.length() > 0)
&& !this.propertySet.getBooleanProperty(PropertyKey.createDatabaseIfNotExist).getValue();
- long clientParam = NativeServerSession.CLIENT_SECURE_CONNECTION | NativeServerSession.CLIENT_PLUGIN_AUTH
- | (capabilityFlags & NativeServerSession.CLIENT_LONG_PASSWORD) //
- | (capabilityFlags & NativeServerSession.CLIENT_PROTOCOL_41) //
- | (capabilityFlags & NativeServerSession.CLIENT_TRANSACTIONS) // Need this to get server status values
- | (capabilityFlags & NativeServerSession.CLIENT_MULTI_RESULTS) // We always allow multiple result sets
- | (capabilityFlags & NativeServerSession.CLIENT_PS_MULTI_RESULTS) // We always allow multiple result sets for SSPS
- | (capabilityFlags & NativeServerSession.CLIENT_LONG_FLAG) //
- | (capabilityFlags & NativeServerSession.CLIENT_DEPRECATE_EOF) //
- | (capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
- | (this.propertySet.getBooleanProperty(PropertyKey.useCompression).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_COMPRESS) : 0)
- | (this.useConnectWithDb ? (capabilityFlags & NativeServerSession.CLIENT_CONNECT_WITH_DB) : 0)
- | (this.propertySet.getBooleanProperty(PropertyKey.useAffectedRows).getValue() ? 0 : (capabilityFlags & NativeServerSession.CLIENT_FOUND_ROWS))
+ long clientParam = capabilityFlags & NativeServerSession.CLIENT_LONG_PASSWORD //
+ | (this.propertySet.getBooleanProperty(PropertyKey.useAffectedRows).getValue() ? //
+ 0 : capabilityFlags & NativeServerSession.CLIENT_FOUND_ROWS) //
+ | capabilityFlags & NativeServerSession.CLIENT_LONG_FLAG //
+ | (this.useConnectWithDb ? capabilityFlags & NativeServerSession.CLIENT_CONNECT_WITH_DB : 0) //
+ | (this.propertySet.getBooleanProperty(PropertyKey.useCompression).getValue() ? //
+ capabilityFlags & NativeServerSession.CLIENT_COMPRESS : 0) //
| (this.propertySet.getBooleanProperty(PropertyKey.allowLoadLocalInfile).getValue()
- || this.propertySet.getStringProperty(PropertyKey.allowLoadLocalInfileInPath).isExplicitlySet()
- ? (capabilityFlags & NativeServerSession.CLIENT_LOCAL_FILES)
- : 0)
- | (this.propertySet.getBooleanProperty(PropertyKey.interactiveClient).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_INTERACTIVE)
- : 0)
- | (this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue()
- ? (capabilityFlags & NativeServerSession.CLIENT_MULTI_STATEMENTS)
- : 0)
- | (this.propertySet.getBooleanProperty(PropertyKey.disconnectOnExpiredPasswords).getValue() ? 0
- : (capabilityFlags & NativeServerSession.CLIENT_CAN_HANDLE_EXPIRED_PASSWORD))
- | (NONE.equals(this.propertySet.getStringProperty(PropertyKey.connectionAttributes).getValue()) ? 0
- : (capabilityFlags & NativeServerSession.CLIENT_CONNECT_ATTRS))
- | (this.propertySet.getEnumProperty(PropertyKey.sslMode).getValue() != SslMode.DISABLED
- ? (capabilityFlags & NativeServerSession.CLIENT_SSL)
- : 0);
-
- // TODO MYSQLCONNJ-437
- // clientParam |= (capabilityFlags & NativeServerSession.CLIENT_SESSION_TRACK);
+ || this.propertySet.getStringProperty(PropertyKey.allowLoadLocalInfileInPath).isExplicitlySet() ? //
+ capabilityFlags & NativeServerSession.CLIENT_LOCAL_FILES : 0) //
+ | capabilityFlags & NativeServerSession.CLIENT_PROTOCOL_41 //
+ | (this.propertySet.getBooleanProperty(PropertyKey.interactiveClient).getValue() ? //
+ capabilityFlags & NativeServerSession.CLIENT_INTERACTIVE : 0) //
+ | (this.propertySet.getEnumProperty(PropertyKey.sslMode).getValue() != SslMode.DISABLED ? //
+ capabilityFlags & NativeServerSession.CLIENT_SSL : 0) //
+ | capabilityFlags & NativeServerSession.CLIENT_TRANSACTIONS // Required to get server status values.
+ | NativeServerSession.CLIENT_SECURE_CONNECTION //
+ | (this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue() ? //
+ capabilityFlags & NativeServerSession.CLIENT_MULTI_STATEMENTS : 0) //
+ | capabilityFlags & NativeServerSession.CLIENT_MULTI_RESULTS // Always allow multiple result sets.
+ | capabilityFlags & NativeServerSession.CLIENT_PS_MULTI_RESULTS // Always allow multiple result sets for SSPS.
+ | NativeServerSession.CLIENT_PLUGIN_AUTH //
+ | (NONE.equals(this.propertySet.getStringProperty(PropertyKey.connectionAttributes).getValue()) ? //
+ 0 : capabilityFlags & NativeServerSession.CLIENT_CONNECT_ATTRS) //
+ | capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA //
+ | (this.propertySet.getBooleanProperty(PropertyKey.disconnectOnExpiredPasswords).getValue() ? //
+ 0 : capabilityFlags & NativeServerSession.CLIENT_CAN_HANDLE_EXPIRED_PASSWORD) //
+ | (this.propertySet.getBooleanProperty(PropertyKey.trackSessionState).getValue() ? //
+ capabilityFlags & NativeServerSession.CLIENT_SESSION_TRACK : 0) //
+ | capabilityFlags & NativeServerSession.CLIENT_DEPRECATE_EOF //
+ | capabilityFlags & NativeServerSession.CLIENT_QUERY_ATTRIBUTES //
+ | capabilityFlags & NativeServerSession.CLIENT_MULTI_FACTOR_AUTHENTICATION;
sessState.setClientParam(clientParam);
@@ -207,7 +208,7 @@ public void connect(ServerSession sessState, String user, String pass, String db
throw ExceptionFactory.createException(Messages.getString("AuthenticationProvider.UnexpectedAuthenticationApproval"), getExceptionInterceptor());
}
- proceedHandshakeWithPluggableAuthentication(sessState, buf);
+ proceedHandshakeWithPluggableAuthentication(buf);
this.password = null;
}
@@ -253,6 +254,8 @@ private void loadAuthenticationPlugins() {
pluginsToInit.add(new CachingSha2PasswordPlugin());
pluginsToInit.add(new MysqlOldPasswordPlugin());
pluginsToInit.add(new AuthenticationLdapSaslClientPlugin());
+ pluginsToInit.add(new AuthenticationKerberosClient());
+ pluginsToInit.add(new AuthenticationOciClient());
// plugins from authenticationPluginClasses connection parameter
String authenticationPluginClasses = this.propertySet.getStringProperty(PropertyKey.authenticationPlugins).getValue();
@@ -322,7 +325,11 @@ private void loadAuthenticationPlugins() {
private AuthenticationPlugin getAuthenticationPlugin(String pluginName) {
AuthenticationPlugin plugin = this.authenticationPlugins.get(pluginName);
- if (plugin != null && !plugin.isReusable()) {
+ if (plugin == null) {
+ return null;
+ }
+
+ if (!plugin.isReusable()) {
try {
plugin = plugin.getClass().newInstance();
} catch (Throwable t) {
@@ -357,14 +364,14 @@ private void checkConfidentiality(AuthenticationPlugin> plugin) {
*
* This method will use registered authentication plugins as requested by the server.
*
- * @param serverSession
- * The current state of the session
* @param challenge
* the Auth Challenge Packet received from server if
* this method is used during the initial connection.
* Otherwise null.
*/
- private void proceedHandshakeWithPluggableAuthentication(ServerSession serverSession, final NativePacketPayload challenge) {
+ private void proceedHandshakeWithPluggableAuthentication(final NativePacketPayload challenge) {
+ ServerSession serverSession = this.protocol.getServerSession();
+
if (this.authenticationPlugins == null) {
loadAuthenticationPlugins();
}
@@ -375,6 +382,8 @@ private void proceedHandshakeWithPluggableAuthentication(ServerSession serverSes
forChangeUser = false;
}
+ serverSession.getCharsetSettings().configurePreHandshake(forChangeUser);
+
/*
* Select the initial plugin:
* Choose the client-side default authentication plugin, if explicitely specified, otherwise choose the server-side default authentication plugin.
@@ -416,64 +425,84 @@ private void proceedHandshakeWithPluggableAuthentication(ServerSession serverSes
NativePacketPayload fromServer = new NativePacketPayload(StringUtils.getBytes(this.seed));
String sourceOfAuthData = this.serverDefaultAuthenticationPluginName;
- boolean old_raw_challenge = false;
- NativePacketPayload last_sent = null;
- NativePacketPayload last_received = challenge;
+ NativePacketPayload lastSent = null;
+ NativePacketPayload lastReceived = challenge;
ArrayList toServer = new ArrayList<>();
+ boolean firstPacket = true;
+
+ // MFA authentication factor
+ int mfaNthFactor = 1;
+
/* Max iterations number */
int counter = 100;
while (0 < counter--) {
/*
* call plugin
*/
- plugin.setAuthenticationParameters(this.username, skipPassword ? null : this.password);
+ plugin.setAuthenticationParameters(this.username, skipPassword ? null : getNthFactorPassword(mfaNthFactor));
plugin.setSourceOfAuthData(sourceOfAuthData);
plugin.nextAuthenticationStep(fromServer, toServer);
/*
* send response to server
*/
- if (toServer.size() > 0) {
+ if (firstPacket) {
+ NativePacketPayload authData = toServer.isEmpty() ? new NativePacketPayload(0) : toServer.get(0);
if (forChangeUser) {
// write COM_CHANGE_USER Packet
- last_sent = createChangeUserPacket(serverSession, plugin.getProtocolPluginName(), toServer);
- this.protocol.send(last_sent, last_sent.getPosition());
- forChangeUser = false; // this branch should be executed only once
-
- } else if (last_received.isAuthMethodSwitchRequestPacket() || last_received.isAuthMoreData() || old_raw_challenge) {
- // write AuthSwitchResponse packet or raw packet(s)
- for (NativePacketPayload buffer : toServer) {
- this.protocol.send(buffer, buffer.getPayloadLength());
- }
-
+ lastSent = createChangeUserPacket(serverSession, plugin.getProtocolPluginName(), authData);
+ this.protocol.send(lastSent, lastSent.getPosition());
} else {
// write HandshakeResponse packet
- last_sent = createHandshakeResponsePacket(serverSession, plugin.getProtocolPluginName(), toServer);
- this.protocol.send(last_sent, last_sent.getPosition());
+ lastSent = createHandshakeResponsePacket(serverSession, plugin.getProtocolPluginName(), authData);
+ this.protocol.send(lastSent, lastSent.getPosition());
}
+ firstPacket = false;
+ } else if (!toServer.isEmpty()) {
+ // write AuthSwitchResponse packet or raw packet(s)
+ toServer.forEach(b -> this.protocol.send(b, b.getPayloadLength()));
}
/*
* read packet from server
*/
- last_received = this.protocol.checkErrorMessage();
- old_raw_challenge = false;
+ lastReceived = this.protocol.checkErrorMessage();
- if (last_received.isOKPacket()) {
+ if (lastReceived.isOKPacket()) {
// read OK packet
- OkPacket ok = OkPacket.parse(last_received, null);
+ OkPacket ok = OkPacket.parse(lastReceived, null);
serverSession.setStatusFlags(ok.getStatusFlags(), true);
+ serverSession.getServerSessionStateController().setSessionStateChanges(ok.getSessionStateChanges());
- // if OK packet then finish handshake
+ // authentication complete
plugin.destroy();
break;
- } else if (last_received.isAuthMethodSwitchRequestPacket()) {
+ } else if (lastReceived.isAuthMethodSwitchRequestPacket()) {
// read AuthSwitchRequest Packet
skipPassword = false;
+ pluginName = lastReceived.readString(StringSelfDataType.STRING_TERM, "ASCII");
+ if (plugin.getProtocolPluginName().equals(pluginName)) {
+ plugin.reset(); // just reset the current one
+ } else {
+ // get new plugin
+ plugin.destroy();
+ plugin = getAuthenticationPlugin(pluginName);
+ if (plugin == null) {
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("AuthenticationProvider.BadAuthenticationPlugin", new Object[] { pluginName }), getExceptionInterceptor());
+ }
+ }
- pluginName = last_received.readString(StringSelfDataType.STRING_TERM, "ASCII");
+ checkConfidentiality(plugin);
+ fromServer = new NativePacketPayload(lastReceived.readBytes(StringSelfDataType.STRING_EOF));
+
+ } else if (lastReceived.isAuthNextFactorPacket()) {
+ // authentication not done yet, there's another MFA iteration
+ mfaNthFactor++;
+ skipPassword = false;
+ pluginName = lastReceived.readString(StringSelfDataType.STRING_TERM, "ASCII");
if (plugin.getProtocolPluginName().equals(pluginName)) {
plugin.reset(); // just reset the current one
} else {
@@ -487,15 +516,14 @@ private void proceedHandshakeWithPluggableAuthentication(ServerSession serverSes
}
checkConfidentiality(plugin);
- fromServer = new NativePacketPayload(StringUtils.getBytes(last_received.readString(StringSelfDataType.STRING_TERM, "ASCII")));
+ fromServer = new NativePacketPayload(lastReceived.readBytes(StringSelfDataType.STRING_EOF));
} else {
- // read raw packet
+ // read raw (from AuthMoreData) packet
if (!this.protocol.versionMeetsMinimum(5, 5, 16)) {
- old_raw_challenge = true;
- last_received.setPosition(last_received.getPosition() - 1);
+ lastReceived.setPosition(lastReceived.getPosition() - 1);
}
- fromServer = new NativePacketPayload(last_received.readBytes(StringSelfDataType.STRING_EOF));
+ fromServer = new NativePacketPayload(lastReceived.readBytes(StringSelfDataType.STRING_EOF));
}
sourceOfAuthData = pluginName;
@@ -513,6 +541,19 @@ private void proceedHandshakeWithPluggableAuthentication(ServerSession serverSes
}
}
+ private String getNthFactorPassword(int nthFactor) {
+ switch (nthFactor) {
+ case 1:
+ return this.password == null ? this.protocol.getPropertySet().getStringProperty(PropertyKey.password1).getValue() : this.password;
+ case 2:
+ return this.protocol.getPropertySet().getStringProperty(PropertyKey.password2).getValue();
+ case 3:
+ return this.protocol.getPropertySet().getStringProperty(PropertyKey.password3).getValue();
+ default:
+ return null;
+ }
+ }
+
private Map getConnectionAttributesMap(String attStr) {
Map attMap = new HashMap<>();
@@ -553,20 +594,6 @@ private void appendConnectionAttributes(NativePacketPayload buf, String attribut
buf.writeBytes(StringLengthDataType.STRING_FIXED, lb.getByteBuffer(), 0, lb.getPosition());
}
- /**
- * Get the Java encoding to be used for the handshake
- * response. Defaults to UTF-8.
- *
- * @return encoding name
- */
- public String getEncodingForHandshake() {
- String enc = this.propertySet.getStringProperty(PropertyKey.characterEncoding).getValue();
- if (enc == null) {
- enc = "UTF-8";
- }
- return enc;
- }
-
public ExceptionInterceptor getExceptionInterceptor() {
return this.exceptionInterceptor;
}
@@ -574,8 +601,6 @@ public ExceptionInterceptor getExceptionInterceptor() {
/**
* Re-authenticates as the given user and password
*
- * @param serverSession
- * current {@link ServerSession}
* @param user
* user name
* @param pass
@@ -584,18 +609,19 @@ public ExceptionInterceptor getExceptionInterceptor() {
* database name
*/
@Override
- public void changeUser(ServerSession serverSession, String user, String pass, String db) {
+ public void changeUser(String user, String pass, String db) {
this.username = user;
this.password = pass;
this.database = db;
- proceedHandshakeWithPluggableAuthentication(serverSession, null);
+ proceedHandshakeWithPluggableAuthentication(null);
this.password = null;
}
- private NativePacketPayload createHandshakeResponsePacket(ServerSession serverSession, String pluginName, ArrayList toServer) {
+ private NativePacketPayload createHandshakeResponsePacket(ServerSession serverSession, String pluginName, NativePacketPayload authData) {
long clientParam = serverSession.getClientParam();
- String enc = getEncodingForHandshake();
+ int collationIndex = serverSession.getCharsetSettings().configurePreHandshake(false);
+ String enc = serverSession.getCharsetSettings().getPasswordCharacterEncoding();
int userLength = this.username == null ? 0 : this.username.length();
NativePacketPayload last_sent = new NativePacketPayload(AUTH_411_OVERHEAD + 7 //
@@ -605,18 +631,18 @@ private NativePacketPayload createHandshakeResponsePacket(ServerSession serverSe
);
last_sent.writeInteger(IntegerDataType.INT4, clientParam);
last_sent.writeInteger(IntegerDataType.INT4, NativeConstants.MAX_PACKET_SIZE);
- last_sent.writeInteger(IntegerDataType.INT1, AuthenticationProvider.getCharsetForHandshake(enc, serverSession.getCapabilities().getServerVersion()));
+ last_sent.writeInteger(IntegerDataType.INT1, collationIndex);
last_sent.writeBytes(StringLengthDataType.STRING_FIXED, new byte[23]); // Set of bytes reserved for future use.
// User/Password data
last_sent.writeBytes(StringSelfDataType.STRING_TERM, StringUtils.getBytes(this.username, enc));
if ((clientParam & NativeServerSession.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) != 0) {
// send lenenc-int length of auth-response and string[n] auth-response
- last_sent.writeBytes(StringSelfDataType.STRING_LENENC, toServer.get(0).readBytes(StringSelfDataType.STRING_EOF));
+ last_sent.writeBytes(StringSelfDataType.STRING_LENENC, authData.readBytes(StringSelfDataType.STRING_EOF));
} else {
// send 1 byte length of auth-response and string[n] auth-response
- last_sent.writeInteger(IntegerDataType.INT1, toServer.get(0).getPayloadLength());
- last_sent.writeBytes(StringSelfDataType.STRING_EOF, toServer.get(0).getByteBuffer());
+ last_sent.writeInteger(IntegerDataType.INT1, authData.getPayloadLength());
+ last_sent.writeBytes(StringSelfDataType.STRING_EOF, authData.getByteBuffer());
}
if (this.useConnectWithDb) {
@@ -632,10 +658,11 @@ private NativePacketPayload createHandshakeResponsePacket(ServerSession serverSe
return last_sent;
}
- private NativePacketPayload createChangeUserPacket(ServerSession serverSession, String pluginName, ArrayList toServer) {
+ private NativePacketPayload createChangeUserPacket(ServerSession serverSession, String pluginName, NativePacketPayload authData) {
// write Auth Response Packet
long clientParam = serverSession.getClientParam();
- String enc = getEncodingForHandshake();
+ int collationIndex = serverSession.getCharsetSettings().configurePreHandshake(false);
+ String enc = serverSession.getCharsetSettings().getPasswordCharacterEncoding();
NativePacketPayload last_sent = new NativePacketPayload(AUTH_411_OVERHEAD + 7 //
+ 48 // passwordLength
@@ -647,10 +674,10 @@ private NativePacketPayload createChangeUserPacket(ServerSession serverSession,
// User/Password data
last_sent.writeBytes(StringSelfDataType.STRING_TERM, StringUtils.getBytes(this.username, enc));
// 'auth-response-len' is limited to one Byte but, in case of success, COM_CHANGE_USER will be followed by an AuthSwitchRequest anyway
- if (toServer.get(0).getPayloadLength() < 256) {
+ if (authData.getPayloadLength() < 256) {
// non-mysql servers may use this information to authenticate without requiring another round-trip
- last_sent.writeInteger(IntegerDataType.INT1, toServer.get(0).getPayloadLength());
- last_sent.writeBytes(StringSelfDataType.STRING_EOF, toServer.get(0).getByteBuffer(), 0, toServer.get(0).getPayloadLength());
+ last_sent.writeInteger(IntegerDataType.INT1, authData.getPayloadLength());
+ last_sent.writeBytes(StringSelfDataType.STRING_EOF, authData.getByteBuffer(), 0, authData.getPayloadLength());
} else {
last_sent.writeInteger(IntegerDataType.INT1, 0);
}
@@ -662,7 +689,7 @@ private NativePacketPayload createChangeUserPacket(ServerSession serverSession,
last_sent.writeInteger(IntegerDataType.INT1, 0);
}
- last_sent.writeInteger(IntegerDataType.INT1, AuthenticationProvider.getCharsetForHandshake(enc, serverSession.getCapabilities().getServerVersion()));
+ last_sent.writeInteger(IntegerDataType.INT1, collationIndex);
last_sent.writeInteger(IntegerDataType.INT1, 0); // two (little-endian) bytes for charset in this packet
// plugin name
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeCapabilities.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeCapabilities.java
index 4bf751552..73d916133 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeCapabilities.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeCapabilities.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -52,27 +52,20 @@ public class NativeCapabilities implements ServerCapabilities {
private int authPluginDataLength = 0;
private boolean serverHasFracSecsSupport = true;
- public NativeCapabilities() {
- }
-
- public NativePacketPayload getInitialHandshakePacket() {
- return this.initialHandshakePacket;
- }
-
- public void setInitialHandshakePacket(NativePacketPayload initialHandshakePacket) {
+ public NativeCapabilities(NativePacketPayload initialHandshakePacket) {
this.initialHandshakePacket = initialHandshakePacket;
// Get the protocol version
- setProtocolVersion((byte) initialHandshakePacket.readInteger(IntegerDataType.INT1));
+ this.protocolVersion = (byte) initialHandshakePacket.readInteger(IntegerDataType.INT1);
try {
- setServerVersion(ServerVersion.parseVersion(initialHandshakePacket.readString(StringSelfDataType.STRING_TERM, "ASCII")));
+ this.serverVersion = ServerVersion.parseVersion(initialHandshakePacket.readString(StringSelfDataType.STRING_TERM, "ASCII"));
// read connection id
- setThreadId(initialHandshakePacket.readInteger(IntegerDataType.INT4));
+ this.threadId = initialHandshakePacket.readInteger(IntegerDataType.INT4);
// read auth-plugin-data-part-1 (string[8])
- setSeed(initialHandshakePacket.readString(StringLengthDataType.STRING_FIXED, "ASCII", 8));
+ this.seed = initialHandshakePacket.readString(StringLengthDataType.STRING_FIXED, "ASCII", 8);
// read filler ([00])
initialHandshakePacket.readInteger(IntegerDataType.INT1);
@@ -85,9 +78,9 @@ public void setInitialHandshakePacket(NativePacketPayload initialHandshakePacket
}
// read character set (1 byte)
- setServerDefaultCollationIndex((int) initialHandshakePacket.readInteger(IntegerDataType.INT1));
+ this.serverDefaultCollationIndex = (int) initialHandshakePacket.readInteger(IntegerDataType.INT1);
// read status flags (2 bytes)
- setStatusFlags((int) initialHandshakePacket.readInteger(IntegerDataType.INT2));
+ this.statusFlags = (int) initialHandshakePacket.readInteger(IntegerDataType.INT2);
// read capability flags (upper 2 bytes)
flags |= (int) initialHandshakePacket.readInteger(IntegerDataType.INT2) << 16;
@@ -117,6 +110,10 @@ public void setInitialHandshakePacket(NativePacketPayload initialHandshakePacket
}
}
+ public NativePacketPayload getInitialHandshakePacket() {
+ return this.initialHandshakePacket;
+ }
+
@Override
public int getCapabilityFlags() {
return this.capabilityFlags;
@@ -127,22 +124,10 @@ public void setCapabilityFlags(int capabilityFlags) {
this.capabilityFlags = capabilityFlags;
}
- public byte getProtocolVersion() {
- return this.protocolVersion;
- }
-
- public void setProtocolVersion(byte protocolVersion) {
- this.protocolVersion = protocolVersion;
- }
-
public ServerVersion getServerVersion() {
return this.serverVersion;
}
- public void setServerVersion(ServerVersion serverVersion) {
- this.serverVersion = serverVersion;
- }
-
public long getThreadId() {
return this.threadId;
}
@@ -155,10 +140,6 @@ public String getSeed() {
return this.seed;
}
- public void setSeed(String seed) {
- this.seed = seed;
- }
-
/**
*
* @return Collation index which server provided in handshake greeting packet
@@ -167,32 +148,14 @@ public int getServerDefaultCollationIndex() {
return this.serverDefaultCollationIndex;
}
- /**
- * Stores collation index which server provided in handshake greeting packet.
- *
- * @param serverDefaultCollationIndex
- * server default collation index
- */
- public void setServerDefaultCollationIndex(int serverDefaultCollationIndex) {
- this.serverDefaultCollationIndex = serverDefaultCollationIndex;
- }
-
public int getStatusFlags() {
return this.statusFlags;
}
- public void setStatusFlags(int statusFlags) {
- this.statusFlags = statusFlags;
- }
-
public int getAuthPluginDataLength() {
return this.authPluginDataLength;
}
- public void setAuthPluginDataLength(int authPluginDataLength) {
- this.authPluginDataLength = authPluginDataLength;
- }
-
@Override
public boolean serverSupportsFracSecs() {
return this.serverHasFracSecsSupport;
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeConstants.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeConstants.java
index a30e15de6..2aa52ec08 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeConstants.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -57,6 +57,7 @@ public class NativeConstants {
public static final int BIN_LEN_DATE = 4;
public static final int BIN_LEN_TIMESTAMP_NO_FRAC = 7;
public static final int BIN_LEN_TIMESTAMP_WITH_MICROS = 11;
+ public static final int BIN_LEN_TIMESTAMP_WITH_TZ = 13;
public static final int BIN_LEN_TIME_NO_FRAC = 8;
public static final int BIN_LEN_TIME_WITH_MICROS = 12;
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeMessageBuilder.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeMessageBuilder.java
index 4acb4e584..2817e8b46 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeMessageBuilder.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeMessageBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2017, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -39,6 +39,11 @@
import com.mysql.cj.util.StringUtils;
public class NativeMessageBuilder implements MessageBuilder {
+ private boolean supportsQueryAttributes = true;
+
+ public NativeMessageBuilder(boolean supportsQueryAttributes) {
+ this.supportsQueryAttributes = supportsQueryAttributes;
+ }
@Override
public NativePacketPayload buildSqlStatement(String statement) {
@@ -58,6 +63,14 @@ public NativePacketPayload buildClose() {
public NativePacketPayload buildComQuery(NativePacketPayload sharedPacket, byte[] query) {
NativePacketPayload packet = sharedPacket != null ? sharedPacket : new NativePacketPayload(query.length + 1);
packet.writeInteger(IntegerDataType.INT1, NativeConstants.COM_QUERY);
+
+ if (this.supportsQueryAttributes) {
+ // CLIENT_QUERY_ATTRIBUTES capability has been negotiated but, since this method is used solely to run queries internally and it is not bound to any
+ // Statement object, no query attributes are ever set.
+ packet.writeInteger(IntegerDataType.INT_LENENC, 0);
+ packet.writeInteger(IntegerDataType.INT_LENENC, 1); // parameter_set_count (always 1)
+ }
+
packet.writeBytes(StringLengthDataType.STRING_FIXED, query);
return packet;
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativePacketPayload.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativePacketPayload.java
index 07e0e7d4f..e44151518 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativePacketPayload.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativePacketPayload.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -29,6 +29,9 @@
package com.mysql.cj.protocol.a;
+import java.util.HashMap;
+import java.util.Map;
+
import com.mysql.cj.Constants;
import com.mysql.cj.Messages;
import com.mysql.cj.exceptions.ExceptionFactory;
@@ -49,7 +52,6 @@
* A position is maintained for reading/writing data. A payload length is
* maintained allowing the PacketPayload to be decoupled from the size of
* the underlying buffer.
- *
*/
public class NativePacketPayload implements Message {
static final int NO_LENGTH_LIMIT = -1;
@@ -62,6 +64,8 @@ public class NativePacketPayload implements Message {
public static final short TYPE_ID_AUTH_SWITCH = 0xFE;
public static final short TYPE_ID_LOCAL_INFILE = 0xFB;
public static final short TYPE_ID_OK = 0;
+ public static final short TYPE_ID_AUTH_MORE_DATA = 0x01;
+ public static final short TYPE_ID_AUTH_NEXT_FACTOR = 0x02;
private int payloadLength = 0;
@@ -71,6 +75,8 @@ public class NativePacketPayload implements Message {
static final int MAX_BYTES_TO_DUMP = 1024;
+ private Map tags = new HashMap<>();
+
@Override
public String toString() {
int numBytes = this.position <= this.payloadLength ? this.position : this.payloadLength;
@@ -208,17 +214,17 @@ public boolean isErrorPacket() {
/**
* Is it a EOF packet.
- * See http://dev.mysql.com/doc/internals/en/packet-EOF_Packet.html
+ * See https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_eof_packet.html
*
* @return true if it is a EOF packet
*/
public final boolean isEOFPacket() {
- return (this.byteBuffer[0] & 0xff) == TYPE_ID_EOF && (getPayloadLength() <= 5);
+ return (this.byteBuffer[0] & 0xff) == TYPE_ID_EOF && (this.payloadLength <= 5);
}
/**
* Is it a Protocol::AuthSwitchRequest packet.
- * See http://dev.mysql.com/doc/internals/en/connection-phase-packets.html
+ * See https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_auth_switch_request.html
*
* @return true if it is a Protocol::AuthSwitchRequest packet
*/
@@ -228,7 +234,7 @@ public final boolean isAuthMethodSwitchRequestPacket() {
/**
* Is it an OK packet.
- * See http://dev.mysql.com/doc/internals/en/packet-OK_Packet.html
+ * See https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html
*
* @return true if it is an OK packet
*/
@@ -238,22 +244,32 @@ public final boolean isOKPacket() {
/**
* Is it an OK packet for ResultSet. Unlike usual 0x00 signature it has 0xfe signature.
- * See http://dev.mysql.com/doc/internals/en/packet-OK_Packet.html
+ * See https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html
*
* @return true if it is an OK packet for ResultSet
*/
public final boolean isResultSetOKPacket() {
- return (this.byteBuffer[0] & 0xff) == TYPE_ID_EOF && (getPayloadLength() < 16777215);
+ return (this.byteBuffer[0] & 0xff) == TYPE_ID_EOF && (this.payloadLength > 5) && (this.payloadLength < 16777215);
}
/**
* Is it a Protocol::AuthMoreData packet.
- * See http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthMoreData
+ * See https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_auth_more_data.html
*
* @return true if it is a Protocol::AuthMoreData packet
*/
- public final boolean isAuthMoreData() {
- return ((this.byteBuffer[0] & 0xff) == 1);
+ public final boolean isAuthMoreDataPacket() {
+ return (this.byteBuffer[0] & 0xff) == TYPE_ID_AUTH_MORE_DATA;
+ }
+
+ /**
+ * Is it a Protocol::AuthNextFactor packet.
+ * See https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_auth_next_factor_request.html
+ *
+ * @return true if it is a Protocol::AuthNextFactor packet
+ */
+ public final boolean isAuthNextFactorPacket() {
+ return (this.byteBuffer[0] & 0xff) == TYPE_ID_AUTH_NEXT_FACTOR;
}
/**
@@ -659,4 +675,29 @@ public static String extractSqlFromPacket(String possibleSqlQuery, NativePacketP
return extractedSql;
}
+ /**
+ * Tag current position with the given key for future reference.
+ *
+ * @param key
+ * the position tag key name.
+ * @return
+ * the previous value of this tag, if there was one, or -1.
+ */
+ public int setTag(String key) {
+ Integer pos = this.tags.put(key, getPosition());
+ return pos == null ? -1 : pos;
+ }
+
+ /**
+ * Gets the value of the position tag for the given key.
+ *
+ * @param key
+ * the position tag key name.
+ * @return
+ * the position value of this tag, if there was one, or -1.
+ */
+ public int getTag(String key) {
+ Integer pos = this.tags.get(key);
+ return pos == null ? -1 : pos;
+ }
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java
index a6d0d978d..e7fa0622a 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -30,11 +30,9 @@
package com.mysql.cj.protocol.a;
import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStreamWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
@@ -68,7 +66,11 @@
import com.mysql.cj.MessageBuilder;
import com.mysql.cj.Messages;
import com.mysql.cj.MysqlType;
+import com.mysql.cj.NativeCharsetSettings;
+import com.mysql.cj.NativeSession;
import com.mysql.cj.Query;
+import com.mysql.cj.QueryAttributesBindValue;
+import com.mysql.cj.QueryAttributesBindings;
import com.mysql.cj.QueryResult;
import com.mysql.cj.ServerPreparedQuery;
import com.mysql.cj.ServerVersion;
@@ -97,7 +99,6 @@
import com.mysql.cj.log.ProfilerEvent;
import com.mysql.cj.log.ProfilerEventHandler;
import com.mysql.cj.protocol.AbstractProtocol;
-import com.mysql.cj.protocol.AuthenticationProvider;
import com.mysql.cj.protocol.ColumnDefinition;
import com.mysql.cj.protocol.ExportControlled;
import com.mysql.cj.protocol.FullReadInputStream;
@@ -187,12 +188,6 @@ public class NativeProtocol extends AbstractProtocol implem
protected Map, ProtocolEntityReader extends ProtocolEntity, ? extends Message>> PROTOCOL_ENTITY_CLASS_TO_TEXT_READER;
protected Map, ProtocolEntityReader extends ProtocolEntity, ? extends Message>> PROTOCOL_ENTITY_CLASS_TO_BINARY_READER;
- /**
- * Does the character set of this connection match the character set of the
- * platform
- */
- protected boolean platformDbCharsetMatches = true; // changed once we've connected.
-
private int statementExecutionDepth = 0;
private List queryInterceptors;
@@ -209,33 +204,7 @@ public class NativeProtocol extends AbstractProtocol implem
*/
private String queryComment = null;
- /**
- * We store the platform 'encoding' here, only used to avoid munging filenames for LOAD DATA LOCAL INFILE...
- */
- private static String jvmPlatformCharset = null;
-
- private NativeMessageBuilder commandBuilder = new NativeMessageBuilder(); // TODO use shared builder
-
- static {
- OutputStreamWriter outWriter = null;
-
- //
- // Use the I/O system to get the encoding (if possible), to avoid security restrictions on System.getProperty("file.encoding") in applets (why is that
- // restricted?)
- //
- try {
- outWriter = new OutputStreamWriter(new ByteArrayOutputStream());
- jvmPlatformCharset = outWriter.getEncoding();
- } finally {
- try {
- if (outWriter != null) {
- outWriter.close();
- }
- } catch (IOException ioEx) {
- // ignore
- }
- }
- }
+ private NativeMessageBuilder commandBuilder = null;
public static NativeProtocol getInstance(Session session, SocketConnection socketConnection, PropertySet propertySet, Log log,
TransactionEventHandler transactionManager) {
@@ -308,6 +277,13 @@ public MessageReader getPacketReader()
return this.packetReader;
}
+ private NativeMessageBuilder getCommandBuilder() {
+ if (this.commandBuilder != null) {
+ return this.commandBuilder;
+ }
+ return this.commandBuilder = new NativeMessageBuilder(this.serverSession.supportsQueryAttributes());
+ }
+
/**
* Negotiates the SSL communications channel used when connecting
* to a MySQL server that understands SSL.
@@ -323,14 +299,13 @@ public void negotiateSSLConnection() {
NativePacketPayload packet = new NativePacketPayload(SSL_REQUEST_LENGTH);
packet.writeInteger(IntegerDataType.INT4, clientParam);
packet.writeInteger(IntegerDataType.INT4, NativeConstants.MAX_PACKET_SIZE);
- packet.writeInteger(IntegerDataType.INT1, AuthenticationProvider.getCharsetForHandshake(this.authProvider.getEncodingForHandshake(),
- this.serverSession.getCapabilities().getServerVersion()));
+ packet.writeInteger(IntegerDataType.INT1, this.serverSession.getCharsetSettings().configurePreHandshake(false));
packet.writeBytes(StringLengthDataType.STRING_FIXED, new byte[23]); // Set of bytes reserved for future use.
send(packet, packet.getPosition());
try {
- this.socketConnection.performTlsHandshake(this.serverSession);
+ this.socketConnection.performTlsHandshake(this.serverSession, this.log);
// i/o streams were replaced, build new packet sender/reader
this.packetSender = new SimplePacketSender(this.socketConnection.getMysqlOutput());
@@ -381,6 +356,8 @@ public void beforeHandshake() {
// Create session state
this.serverSession = new NativeServerSession(this.propertySet);
+ this.serverSession.setCharsetSettings(new NativeCharsetSettings((NativeSession) this.session));
+
// Read the first packet
this.serverSession.setCapabilities(readServerCapabilities());
@@ -502,11 +479,7 @@ public NativeCapabilities readServerCapabilities() {
rejectProtocol(buf);
}
- NativeCapabilities serverCapabilities = new NativeCapabilities();
- serverCapabilities.setInitialHandshakePacket(buf);
-
- return serverCapabilities;
-
+ return new NativeCapabilities(buf);
}
@Override
@@ -521,12 +494,13 @@ public void changeDatabase(String database) {
}
try {
- sendCommand(this.commandBuilder.buildComInitDb(getSharedSendPacket(), database), false, 0);
+ sendCommand(getCommandBuilder().buildComInitDb(getSharedSendPacket(), database), false, 0);
} catch (CJException ex) {
if (this.getPropertySet().getBooleanProperty(PropertyKey.createDatabaseIfNotExist).getValue()) {
- sendCommand(this.commandBuilder.buildComQuery(getSharedSendPacket(), "CREATE DATABASE IF NOT EXISTS " + database), false, 0);
+ sendCommand(getCommandBuilder().buildComQuery(getSharedSendPacket(),
+ "CREATE DATABASE IF NOT EXISTS " + StringUtils.quoteIdentifier(database, true)), false, 0);
- sendCommand(this.commandBuilder.buildComInitDb(getSharedSendPacket(), database), false, 0);
+ sendCommand(getCommandBuilder().buildComInitDb(getSharedSendPacket(), database), false, 0);
} else {
throw ExceptionFactory.createCommunicationsException(this.getPropertySet(), this.serverSession, this.getPacketSentTimeHolder(),
this.getPacketReceivedTimeHolder(), ex, getExceptionInterceptor());
@@ -551,6 +525,22 @@ public final NativePacketPayload readMessage(NativePacketPayload reuse) {
}
}
+ public final NativePacketPayload probeMessage(NativePacketPayload reuse) {
+ try {
+ NativePacketHeader header = this.packetReader.probeHeader();
+ NativePacketPayload buf = this.packetReader.probeMessage(Optional.ofNullable(reuse), header);
+ this.packetSequence = header.getMessageSequence();
+ return buf;
+
+ } catch (IOException ioEx) {
+ throw ExceptionFactory.createCommunicationsException(this.propertySet, this.serverSession, this.getPacketSentTimeHolder(),
+ this.getPacketReceivedTimeHolder(), ioEx, getExceptionInterceptor());
+ } catch (OutOfMemoryError oom) {
+ throw ExceptionFactory.createException(oom.getMessage(), MysqlErrorNumbers.SQL_STATE_MEMORY_ALLOCATION_ERROR, 0, false, oom,
+ this.exceptionInterceptor);
+ }
+ }
+
/**
* @param packet
* {@link Message}
@@ -735,7 +725,7 @@ public void checkErrorMessage(NativePacketPayload resultPacket) {
String xOpen = null;
- serverErrorMessage = resultPacket.readString(StringSelfDataType.STRING_TERM, this.serverSession.getErrorMessageEncoding());
+ serverErrorMessage = resultPacket.readString(StringSelfDataType.STRING_TERM, this.serverSession.getCharsetSettings().getErrorMessageEncoding());
if (serverErrorMessage.charAt(0) == '#') {
@@ -862,7 +852,7 @@ public final T sendQueryString(Query callingQuery, String
// We don't know exactly how many bytes we're going to get from the query. Since we're dealing with UTF-8, the max is 4, so pad it
// (4 * query) + space for headers
- int packLength = 1 + (query.length() * 4) + 2;
+ int packLength = 1 /* com_query */ + (query.length() * 4) + 2;
byte[] commentAsBytes = null;
@@ -873,22 +863,68 @@ public final T sendQueryString(Query callingQuery, String
packLength += 6; // for /*[space] [space]*/
}
+ boolean supportsQueryAttributes = this.serverSession.supportsQueryAttributes();
+ QueryAttributesBindings queryAttributes = null;
+
+ if (!supportsQueryAttributes && callingQuery != null && callingQuery.getQueryAttributesBindings().getCount() > 0) {
+ this.log.logWarn(Messages.getString("QueryAttributes.SetButNotSupported"));
+ }
+
+ if (supportsQueryAttributes) {
+ if (callingQuery != null) {
+ queryAttributes = callingQuery.getQueryAttributesBindings();
+ }
+
+ if (queryAttributes != null && queryAttributes.getCount() > 0) {
+ packLength += 9 /* parameter_count */ + 1 /* parameter_set_count */;
+ packLength += (queryAttributes.getCount() + 7) / 8 /* null_bitmap */ + 1 /* new_params_bind_flag */;
+ for (int i = 0; i < queryAttributes.getCount(); i++) {
+ QueryAttributesBindValue queryAttribute = queryAttributes.getAttributeValue(i);
+ packLength += 2 /* parameter_type */ + queryAttribute.getName().length() /* parameter_name */ + queryAttribute.getBoundLength();
+ }
+ } else {
+ packLength += 1 /* parameter_count */ + 1 /* parameter_set_count */;
+ }
+ }
+
// TODO decide how to safely use the shared this.sendPacket
- //if (this.sendPacket == null) {
NativePacketPayload sendPacket = new NativePacketPayload(packLength);
- //}
sendPacket.setPosition(0);
-
sendPacket.writeInteger(IntegerDataType.INT1, NativeConstants.COM_QUERY);
+ if (supportsQueryAttributes) {
+ if (queryAttributes != null && queryAttributes.getCount() > 0) {
+ sendPacket.writeInteger(IntegerDataType.INT_LENENC, queryAttributes.getCount());
+ sendPacket.writeInteger(IntegerDataType.INT_LENENC, 1); // parameter_set_count (always 1)
+ byte[] nullBitsBuffer = new byte[(queryAttributes.getCount() + 7) / 8];
+ for (int i = 0; i < queryAttributes.getCount(); i++) {
+ if (queryAttributes.getAttributeValue(i).isNull()) {
+ nullBitsBuffer[i >>> 3] |= 1 << (i & 7);
+ }
+ }
+ sendPacket.writeBytes(StringLengthDataType.STRING_VAR, nullBitsBuffer);
+ sendPacket.writeInteger(IntegerDataType.INT1, 1); // new_params_bind_flag (always 1)
+ queryAttributes.runThroughAll(a -> {
+ sendPacket.writeInteger(IntegerDataType.INT2, a.getType());
+ sendPacket.writeBytes(StringSelfDataType.STRING_LENENC, a.getName().getBytes());
+ });
+ ValueEncoder valueEncoder = new ValueEncoder(sendPacket, characterEncoding, this.serverSession.getDefaultTimeZone());
+ queryAttributes.runThroughAll(a -> valueEncoder.encodeValue(a.getValue(), a.getType()));
+ } else {
+ sendPacket.writeInteger(IntegerDataType.INT_LENENC, 0);
+ sendPacket.writeInteger(IntegerDataType.INT_LENENC, 1); // parameter_set_count (always 1)
+ }
+ }
+ sendPacket.setTag("QUERY");
+
if (commentAsBytes != null) {
sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, Constants.SLASH_STAR_SPACE_AS_BYTES);
sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, commentAsBytes);
sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, Constants.SPACE_STAR_SLASH_SPACE_AS_BYTES);
}
- if (!this.platformDbCharsetMatches && StringUtils.startsWithIgnoreCaseAndWs(query, "LOAD DATA")) {
+ if (!this.session.getServerSession().getCharsetSettings().doesPlatformDbCharsetMatches() && StringUtils.startsWithIgnoreCaseAndWs(query, "LOAD DATA")) {
sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, StringUtils.getBytes(query));
} else {
sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, StringUtils.getBytes(query, characterEncoding));
@@ -927,8 +963,8 @@ public final T sendQueryPacket(Query callingQuery, NativeP
byte[] queryBuf = queryPacket.getByteBuffer();
int oldPacketPosition = queryPacket.getPosition(); // save the packet position
-
- LazyString query = new LazyString(queryBuf, 1, (oldPacketPosition - 1));
+ int queryPosition = queryPacket.getTag("QUERY");
+ LazyString query = new LazyString(queryBuf, queryPosition, (oldPacketPosition - queryPosition));
try {
@@ -967,9 +1003,9 @@ public final T sendQueryPacket(Query callingQuery, NativeP
long fetchEndTime = this.profileSQL ? getCurrentTimeNanosOrMillis() : 0L;
// Extract the actual query from the network packet
- boolean truncated = oldPacketPosition > this.maxQuerySizeToLog.getValue();
- int extractPosition = truncated ? this.maxQuerySizeToLog.getValue() + 1 : oldPacketPosition;
- String extractedQuery = StringUtils.toString(queryBuf, 1, (extractPosition - 1));
+ boolean truncated = oldPacketPosition - queryPosition > this.maxQuerySizeToLog.getValue();
+ int extractPosition = truncated ? this.maxQuerySizeToLog.getValue() + queryPosition : oldPacketPosition;
+ String extractedQuery = StringUtils.toString(queryBuf, queryPosition, (extractPosition - queryPosition));
if (truncated) {
extractedQuery += Messages.getString("Protocol.2");
}
@@ -984,8 +1020,8 @@ public final T sendQueryPacket(Query callingQuery, NativeP
this.queryTimingUnits, Long.valueOf(queryDuration), extractedQuery }));
if (this.propertySet.getBooleanProperty(PropertyKey.explainSlowQueries).getValue()) {
- if (oldPacketPosition < MAX_QUERY_SIZE_TO_EXPLAIN) {
- queryPacket.setPosition(1); // skip first byte
+ if (oldPacketPosition - queryPosition < MAX_QUERY_SIZE_TO_EXPLAIN) {
+ queryPacket.setPosition(queryPosition); // skip until the query is located in the packet
explainSlowQuery(query.toString(), extractedQuery);
} else {
this.log.logWarn(Messages.getString("Protocol.3", new Object[] { MAX_QUERY_SIZE_TO_EXPLAIN }));
@@ -1170,7 +1206,7 @@ public void explainSlowQuery(String query, String truncatedQuery) {
|| (versionMeetsMinimum(5, 6, 3) && StringUtils.startsWithIgnoreCaseAndWs(truncatedQuery, EXPLAINABLE_STATEMENT_EXTENSION) != -1)) {
try {
- NativePacketPayload resultPacket = sendCommand(this.commandBuilder.buildComQuery(getSharedSendPacket(), "EXPLAIN " + query), false, 0);
+ NativePacketPayload resultPacket = sendCommand(getCommandBuilder().buildComQuery(getSharedSendPacket(), "EXPLAIN " + query), false, 0);
Resultset rs = readAllResults(-1, false, resultPacket, false, null, new ResultsetFactory(Type.FORWARD_ONLY, null));
@@ -1233,7 +1269,7 @@ public final void quit() {
this.packetSequence = -1;
NativePacketPayload packet = new NativePacketPayload(1);
- send(this.commandBuilder.buildComQuit(packet), packet.getPosition());
+ send(getCommandBuilder().buildComQuit(packet), packet.getPosition());
} finally {
this.socketConnection.forceClose();
this.localInfileInputStream = null;
@@ -1285,27 +1321,7 @@ public void changeUser(String user, String password, String database) {
this.packetSender = this.packetSender.undecorateAll();
this.packetReader = this.packetReader.undecorateAll();
- this.authProvider.changeUser(this.serverSession, user, password, database);
- }
-
- /**
- * Determines if the database charset is the same as the platform charset
- */
- public void checkForCharsetMismatch() {
- String characterEncoding = this.propertySet.getStringProperty(PropertyKey.characterEncoding).getValue();
- if (characterEncoding != null) {
- String encodingToCheck = jvmPlatformCharset;
-
- if (encodingToCheck == null) {
- encodingToCheck = Constants.PLATFORM_ENCODING;
- }
-
- if (encodingToCheck == null) {
- this.platformDbCharsetMatches = false;
- } else {
- this.platformDbCharsetMatches = encodingToCheck.equals(characterEncoding);
- }
- }
+ this.authProvider.changeUser(user, password, database);
}
protected boolean useNanosForElapsedTime() {
@@ -1350,8 +1366,7 @@ public void connect(String user, String password, String database) {
beforeHandshake();
- this.authProvider.connect(this.serverSession, user, password, database);
-
+ this.authProvider.connect(user, password, database);
}
protected boolean isDataAvailable() {
@@ -1393,22 +1408,6 @@ public void dumpPacketRingBuffer() {
}
}
- public boolean doesPlatformDbCharsetMatches() {
- return this.platformDbCharsetMatches;
- }
-
- public String getPasswordCharacterEncoding() {
- String encoding;
- if ((encoding = this.propertySet.getStringProperty(PropertyKey.passwordCharacterEncoding).getStringValue()) != null) {
- return encoding;
- }
- if ((encoding = this.propertySet.getStringProperty(PropertyKey.characterEncoding).getValue()) != null) {
- return encoding;
- }
- return "UTF-8";
-
- }
-
public boolean versionMeetsMinimum(int major, int minor, int subminor) {
return this.serverSession.getServerVersion().meetsMinimum(new ServerVersion(major, minor, subminor));
}
@@ -1679,7 +1678,7 @@ public final T readServerStatusForResultSets(NativePacketPayload rowPacket,
T result = null;
if (rowPacket.isEOFPacket()) {
// read EOF packet
- rowPacket.readInteger(IntegerDataType.INT1); // skips the 'last packet' flag (packet signature)
+ rowPacket.setPosition(1); // skip the packet signature header
this.warningCount = (int) rowPacket.readInteger(IntegerDataType.INT2);
if (this.warningCount > 0) {
this.hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
@@ -1689,10 +1688,11 @@ public final T readServerStatusForResultSets(NativePacketPayload rowPacket,
checkTransactionState();
} else {
// read OK packet
- OkPacket ok = OkPacket.parse(rowPacket, this.serverSession.getErrorMessageEncoding());
+ OkPacket ok = OkPacket.parse(rowPacket, this.serverSession.getCharsetSettings().getErrorMessageEncoding());
result = (T) ok;
this.serverSession.setStatusFlags(ok.getStatusFlags(), saveOldStatus);
+ this.serverSession.getServerSessionStateController().setSessionStateChanges(ok.getSessionStateChanges());
checkTransactionState();
this.warningCount = ok.getWarningCount();
@@ -1935,7 +1935,7 @@ public void unsetStreamingData(ResultsetRows streamer) {
public void scanForAndThrowDataTruncation() {
if (this.streamingData == null && this.propertySet.getBooleanProperty(PropertyKey.jdbcCompliantTruncation).getValue() && getWarningCount() > 0) {
int warningCountOld = getWarningCount();
- convertShowWarningsToSQLWarnings(getWarningCount(), true);
+ convertShowWarningsToSQLWarnings(true);
setWarningCount(warningCountOld);
}
}
@@ -1969,7 +1969,7 @@ private void appendDeadlockStatusInformation(Session sess, String xOpen, StringB
&& (xOpen.startsWith("40") || xOpen.startsWith("41")) && getStreamingData() == null) {
try {
- NativePacketPayload resultPacket = sendCommand(this.commandBuilder.buildComQuery(getSharedSendPacket(), "SHOW ENGINE INNODB STATUS"), false, 0);
+ NativePacketPayload resultPacket = sendCommand(getCommandBuilder().buildComQuery(getSharedSendPacket(), "SHOW ENGINE INNODB STATUS"), false, 0);
Resultset rs = readAllResults(-1, false, resultPacket, false, null, new ResultsetFactory(Type.FORWARD_ONLY, null));
@@ -2085,14 +2085,16 @@ private StringBuilder appendResultSetSlashGStyle(StringBuilder appendTo, Results
* If 'forTruncationOnly' is true, only looks for truncation warnings, and
* actually throws DataTruncation as an exception.
*
- * @param warningCountIfKnown
- * the warning count (if known), otherwise set it to 0.
* @param forTruncationOnly
* if this method should only scan for data truncation warnings
*
* @return the SQLWarning chain (or null if no warnings)
*/
- public SQLWarning convertShowWarningsToSQLWarnings(int warningCountIfKnown, boolean forTruncationOnly) {
+ public SQLWarning convertShowWarningsToSQLWarnings(boolean forTruncationOnly) {
+ if (this.warningCount == 0) {
+ return null;
+ }
+
SQLWarning currentWarning = null;
ResultsetRows rows = null;
@@ -2104,9 +2106,9 @@ public SQLWarning convertShowWarningsToSQLWarnings(int warningCountIfKnown, bool
* | Warning | 1265 | Data truncated for column 'field1' at row 1 |
* +---------+------+---------------------------------------------+
*/
- NativePacketPayload resultPacket = sendCommand(this.commandBuilder.buildComQuery(getSharedSendPacket(), "SHOW WARNINGS"), false, 0);
+ NativePacketPayload resultPacket = sendCommand(getCommandBuilder().buildComQuery(getSharedSendPacket(), "SHOW WARNINGS"), false, 0);
- Resultset warnRs = readAllResults(-1, warningCountIfKnown > 99 /* stream large warning counts */, resultPacket, false, null,
+ Resultset warnRs = readAllResults(-1, this.warningCount > 99 /* stream large warning counts */, resultPacket, false, null,
new ResultsetFactory(Type.FORWARD_ONLY, Concurrency.READ_ONLY));
int codeFieldIndex = warnRs.getColumnDefinition().findColumn("Code", false, 1) - 1;
@@ -2209,7 +2211,7 @@ public void configureTimeZone() {
}
query.append("'");
- sendCommand(this.commandBuilder.buildComQuery(null, query.toString()), false, 0);
+ sendCommand(getCommandBuilder().buildComQuery(null, query.toString()), false, 0);
}
}
@@ -2217,8 +2219,8 @@ public void configureTimeZone() {
public void initServerSession() {
configureTimeZone();
- if (this.session.getServerSession().getServerVariables().containsKey("max_allowed_packet")) {
- int serverMaxAllowedPacket = this.session.getServerSession().getServerVariable("max_allowed_packet", -1);
+ if (this.serverSession.getServerVariables().containsKey("max_allowed_packet")) {
+ int serverMaxAllowedPacket = this.serverSession.getServerVariable("max_allowed_packet", -1);
// use server value if maxAllowedPacket hasn't been given, or max_allowed_packet is smaller
if (serverMaxAllowedPacket != -1 && (!this.maxAllowedPacket.isExplicitlySet() || serverMaxAllowedPacket < this.maxAllowedPacket.getValue())) {
@@ -2241,5 +2243,7 @@ public void initServerSession() {
blobSendChunkSize.setValue(allowedBlobSendChunkSize);
}
}
+
+ this.serverSession.getCharsetSettings().configurePostHandshake(false);
}
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeServerSession.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeServerSession.java
index 2f51630b7..be5efa266 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeServerSession.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeServerSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -33,8 +33,7 @@
import java.util.Map;
import java.util.TimeZone;
-import com.mysql.cj.CharsetMapping;
-import com.mysql.cj.Messages;
+import com.mysql.cj.CharsetSettings;
import com.mysql.cj.ServerVersion;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.conf.PropertySet;
@@ -43,7 +42,7 @@
import com.mysql.cj.exceptions.WrongArgumentException;
import com.mysql.cj.protocol.ServerCapabilities;
import com.mysql.cj.protocol.ServerSession;
-import com.mysql.cj.util.StringUtils;
+import com.mysql.cj.protocol.ServerSessionStateController;
import com.mysql.cj.util.TimeUtil;
public class NativeServerSession implements ServerSession {
@@ -56,12 +55,13 @@ public class NativeServerSession implements ServerSession {
public static final int SERVER_STATUS_CURSOR_EXISTS = 64;
public static final int SERVER_STATUS_LAST_ROW_SENT = 128; // The server status for 'last-row-sent'
public static final int SERVER_QUERY_WAS_SLOW = 2048;
+ public static final int SERVER_SESSION_STATE_CHANGED = 1 << 14; // 16384
public static final int CLIENT_LONG_PASSWORD = 0x00000001; /* new more secure passwords */
public static final int CLIENT_FOUND_ROWS = 0x00000002;
public static final int CLIENT_LONG_FLAG = 0x00000004; /* Get all column flags */
public static final int CLIENT_CONNECT_WITH_DB = 0x00000008;
- public static final int CLIENT_COMPRESS = 0x00000020; /* Can use compression protcol */
+ public static final int CLIENT_COMPRESS = 0x00000020; /* Can use compression protocol */
public static final int CLIENT_LOCAL_FILES = 0x00000080; /* Can use LOAD DATA LOCAL */
public static final int CLIENT_PROTOCOL_41 = 0x00000200; // for > 4.1.1
public static final int CLIENT_INTERACTIVE = 0x00000400;
@@ -78,38 +78,20 @@ public class NativeServerSession implements ServerSession {
public static final int CLIENT_CAN_HANDLE_EXPIRED_PASSWORD = 0x00400000;
public static final int CLIENT_SESSION_TRACK = 0x00800000;
public static final int CLIENT_DEPRECATE_EOF = 0x01000000;
+ public static final int CLIENT_QUERY_ATTRIBUTES = 0x08000000;
+ public static final int CLIENT_MULTI_FACTOR_AUTHENTICATION = 0x10000000;
private PropertySet propertySet;
private NativeCapabilities capabilities;
private int oldStatusFlags = 0;
private int statusFlags = 0;
- private int serverDefaultCollationIndex;
private long clientParam = 0;
+ private NativeServerSessionStateController serverSessionStateController;
/** The map of server variables that we retrieve at connection init. */
private Map serverVariables = new HashMap<>();
- public Map indexToCustomMysqlCharset = null;
-
- public Map mysqlCharsetToCustomMblen = null;
-
- /**
- * What character set is the metadata returned in?
- */
- private String characterSetMetadata = null;
- private int metadataCollationIndex;
-
- /**
- * The character set we want results and result metadata returned in (null ==
- * results in any charset, metadata in UTF-8).
- */
- private String characterSetResultsOnServer = null;
-
- /**
- * The (Java) encoding used to interpret error messages received from the server.
- * We use character_set_results (since MySQL 5.5) if it is not null or UTF-8 otherwise.
- */
- private String errorMessageEncoding = "Cp1252"; // to begin with, changes after we talk to the server
+ private CharsetSettings charsetSettings;
/** Are we in autoCommit mode? */
private boolean autoCommit = true;
@@ -124,9 +106,7 @@ public class NativeServerSession implements ServerSession {
public NativeServerSession(PropertySet propertySet) {
this.propertySet = propertySet;
this.cacheDefaultTimeZone = this.propertySet.getBooleanProperty(PropertyKey.cacheDefaultTimeZone);
-
- // preconfigure some server variables which are consulted before their initialization from server
- this.serverVariables.put("character_set_server", "utf8");
+ this.serverSessionStateController = new NativeServerSessionStateController();
}
@Override
@@ -232,27 +212,23 @@ public void setClientParam(long clientParam) {
}
@Override
- public boolean useMultiResults() {
- return (this.clientParam & CLIENT_MULTI_RESULTS) != 0 || (this.clientParam & CLIENT_PS_MULTI_RESULTS) != 0;
- }
-
- public boolean isEOFDeprecated() {
- return (this.clientParam & CLIENT_DEPRECATE_EOF) != 0;
+ public boolean hasLongColumnInfo() {
+ return (this.clientParam & CLIENT_LONG_FLAG) != 0;
}
@Override
- public int getServerDefaultCollationIndex() {
- return this.serverDefaultCollationIndex;
+ public boolean useMultiResults() {
+ return (this.clientParam & CLIENT_MULTI_RESULTS) != 0 || (this.clientParam & CLIENT_PS_MULTI_RESULTS) != 0;
}
@Override
- public void setServerDefaultCollationIndex(int serverDefaultCollationIndex) {
- this.serverDefaultCollationIndex = serverDefaultCollationIndex;
+ public boolean isEOFDeprecated() {
+ return (this.clientParam & CLIENT_DEPRECATE_EOF) != 0;
}
@Override
- public boolean hasLongColumnInfo() {
- return (this.clientParam & CLIENT_LONG_FLAG) != 0;
+ public boolean supportsQueryAttributes() {
+ return (this.clientParam & CLIENT_QUERY_ATTRIBUTES) != 0;
}
@Override
@@ -281,12 +257,6 @@ public void setServerVariables(Map serverVariables) {
this.serverVariables = serverVariables;
}
- public boolean characterSetNamesMatches(String mysqlEncodingName) {
- // set names is equivalent to character_set_client ..._results and ..._connection, but we set _results later, so don't check it here.
- return (mysqlEncodingName != null && mysqlEncodingName.equalsIgnoreCase(getServerVariable("character_set_client"))
- && mysqlEncodingName.equalsIgnoreCase(getServerVariable("character_set_connection")));
- }
-
public final ServerVersion getServerVersion() {
return this.capabilities.getServerVersion();
}
@@ -323,159 +293,6 @@ public boolean isSetNeededForAutoCommitMode(boolean autoCommitFlag, boolean elid
return true;
}
- @Override
- public String getErrorMessageEncoding() {
- return this.errorMessageEncoding;
- }
-
- @Override
- public void setErrorMessageEncoding(String errorMessageEncoding) {
- this.errorMessageEncoding = errorMessageEncoding;
- }
-
- public String getServerDefaultCharset() {
- String charset = null;
- if (this.indexToCustomMysqlCharset != null) {
- charset = this.indexToCustomMysqlCharset.get(getServerDefaultCollationIndex());
- }
- if (charset == null) {
- charset = CharsetMapping.getMysqlCharsetNameForCollationIndex(getServerDefaultCollationIndex());
- }
- return charset != null ? charset : getServerVariable("character_set_server");
- }
-
- public int getMaxBytesPerChar(String javaCharsetName) {
- return getMaxBytesPerChar(null, javaCharsetName);
- }
-
- public int getMaxBytesPerChar(Integer charsetIndex, String javaCharsetName) {
-
- String charset = null;
- int res = 1;
-
- // if we can get it by charsetIndex just doing it
-
- // 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) {
- charset = this.indexToCustomMysqlCharset.get(charsetIndex);
- }
- // checking against static maps if no custom charset found
- if (charset == null) {
- charset = CharsetMapping.getMysqlCharsetNameForCollationIndex(charsetIndex);
- }
-
- // if we didn't find charset name by index
- if (charset == null) {
- charset = CharsetMapping.getMysqlCharsetForJavaEncoding(javaCharsetName, getServerVersion());
- }
-
- // checking against dynamic maps in connection
- Integer mblen = null;
- if (this.mysqlCharsetToCustomMblen != null) {
- mblen = this.mysqlCharsetToCustomMblen.get(charset);
- }
-
- // checking against static maps
- if (mblen == null) {
- mblen = CharsetMapping.getMblen(charset);
- }
-
- if (mblen != null) {
- res = mblen.intValue();
- }
-
- return res; // we don't know
- }
-
- public String getEncodingForIndex(int charsetIndex) {
- String javaEncoding = null;
-
- String characterEncoding = this.propertySet.getStringProperty(PropertyKey.characterEncoding).getValue();
-
- if (charsetIndex != NativeConstants.NO_CHARSET_INFO) {
- try {
- // 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, characterEncoding);
- }
- }
- // checking against static maps if no custom charset found
- if (javaEncoding == null) {
- javaEncoding = CharsetMapping.getJavaEncodingForCollationIndex(charsetIndex, characterEncoding);
- }
-
- } catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
- throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.11", new Object[] { charsetIndex }));
- }
-
- // Punt
- if (javaEncoding == null) {
- javaEncoding = characterEncoding;
- }
- } else {
- javaEncoding = characterEncoding;
- }
-
- return javaEncoding;
- }
-
- public void configureCharacterSets() {
- //
- // We need to figure out what character set metadata and error messages will be returned in, and then map them to Java encoding names
- //
- // We've already set it, and it might be different than what was originally on the server, which is why we use the "special" key to retrieve it
- String characterSetResultsOnServerMysql = getServerVariable(LOCAL_CHARACTER_SET_RESULTS);
-
- if (characterSetResultsOnServerMysql == null || StringUtils.startsWithIgnoreCaseAndWs(characterSetResultsOnServerMysql, "NULL")
- || characterSetResultsOnServerMysql.length() == 0) {
- String defaultMetadataCharsetMysql = getServerVariable("character_set_system");
- String defaultMetadataCharset = null;
-
- if (defaultMetadataCharsetMysql != null) {
- defaultMetadataCharset = CharsetMapping.getJavaEncodingForMysqlCharset(defaultMetadataCharsetMysql);
- } else {
- defaultMetadataCharset = "UTF-8";
- }
-
- this.characterSetMetadata = defaultMetadataCharset;
- setErrorMessageEncoding("UTF-8");
- } else {
- this.characterSetResultsOnServer = CharsetMapping.getJavaEncodingForMysqlCharset(characterSetResultsOnServerMysql);
- this.characterSetMetadata = this.characterSetResultsOnServer;
- setErrorMessageEncoding(this.characterSetResultsOnServer);
- }
-
- this.metadataCollationIndex = CharsetMapping.getCollationIndexForJavaEncoding(this.characterSetMetadata, getServerVersion());
- }
-
- public String getCharacterSetMetadata() {
- return this.characterSetMetadata;
- }
-
- public void setCharacterSetMetadata(String characterSetMetadata) {
- this.characterSetMetadata = characterSetMetadata;
- }
-
- public int getMetadataCollationIndex() {
- return this.metadataCollationIndex;
- }
-
- public void setMetadataCollationIndex(int metadataCollationIndex) {
- this.metadataCollationIndex = metadataCollationIndex;
- }
-
- public String getCharacterSetResultsOnServer() {
- return this.characterSetResultsOnServer;
- }
-
- public void setCharacterSetResultsOnServer(String characterSetResultsOnServer) {
- this.characterSetResultsOnServer = characterSetResultsOnServer;
- }
-
public void preserveOldTransactionState() {
this.statusFlags |= this.oldStatusFlags & SERVER_STATUS_IN_TRANS;
}
@@ -517,16 +334,6 @@ public boolean isServerTruncatesFracSecs() {
return sqlModeAsString != null && sqlModeAsString.indexOf("TIME_TRUNCATE_FRACTIONAL") != -1;
}
- @Override
- public long getThreadId() {
- return this.capabilities.getThreadId();
- }
-
- @Override
- public void setThreadId(long threadId) {
- this.capabilities.setThreadId(threadId);
- }
-
public boolean isAutoCommit() {
return this.autoCommit;
}
@@ -563,4 +370,19 @@ public TimeZone getDefaultTimeZone() {
}
return TimeZone.getDefault();
}
+
+ @Override
+ public ServerSessionStateController getServerSessionStateController() {
+ return this.serverSessionStateController;
+ }
+
+ @Override
+ public CharsetSettings getCharsetSettings() {
+ return this.charsetSettings;
+ }
+
+ @Override
+ public void setCharsetSettings(CharsetSettings charsetSettings) {
+ this.charsetSettings = charsetSettings;
+ }
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeServerSessionStateController.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeServerSessionStateController.java
new file mode 100644
index 000000000..bb8a4991e
--- /dev/null
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeServerSessionStateController.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is also distributed with certain software (including but not
+ * limited to OpenSSL) that is licensed under separate terms, as designated in a
+ * particular file or component or in included license documentation. The
+ * authors of MySQL hereby grant you an additional permission to link the
+ * program and your derivative works with the separately licensed software that
+ * they have included with MySQL.
+ *
+ * Without limiting anything contained in the foregoing, this file, which is
+ * part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
+ * version 1.0, a copy of which can be found at
+ * http://oss.oracle.com/licenses/universal-foss-exception.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package com.mysql.cj.protocol.a;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.mysql.cj.protocol.ServerSessionStateController;
+import com.mysql.cj.protocol.a.NativeConstants.IntegerDataType;
+import com.mysql.cj.protocol.a.NativeConstants.StringLengthDataType;
+import com.mysql.cj.protocol.a.NativeConstants.StringSelfDataType;
+
+public class NativeServerSessionStateController implements ServerSessionStateController {
+ private NativeServerSessionStateChanges sessionStateChanges;
+ private List> listeners;
+
+ @Override
+ public void setSessionStateChanges(ServerSessionStateChanges changes) {
+ this.sessionStateChanges = (NativeServerSessionStateChanges) changes;
+ if (this.listeners != null) {
+ for (WeakReference wr : this.listeners) {
+ SessionStateChangesListener l = wr.get();
+ if (l != null) {
+ l.handleSessionStateChanges(changes);
+ } else {
+ this.listeners.remove(wr);
+ }
+ }
+ }
+ }
+
+ @Override
+ public NativeServerSessionStateChanges getSessionStateChanges() {
+ return this.sessionStateChanges;
+ }
+
+ @Override
+ public void addSessionStateChangesListener(SessionStateChangesListener l) {
+ if (this.listeners == null) {
+ this.listeners = new ArrayList<>();
+ }
+ for (WeakReference wr : this.listeners) {
+ if (l.equals(wr.get())) {
+ return;
+ }
+ }
+ this.listeners.add(new WeakReference<>(l));
+ }
+
+ @Override
+ public void removeSessionStateChangesListener(SessionStateChangesListener listener) {
+ if (this.listeners != null) {
+ for (WeakReference wr : this.listeners) {
+ SessionStateChangesListener l = wr.get();
+ if (l == null || l.equals(listener)) {
+ this.listeners.remove(wr);
+ break;
+ }
+ }
+ }
+ }
+
+ public static class NativeServerSessionStateChanges implements ServerSessionStateChanges {
+ private List sessionStateChanges = new ArrayList<>();
+
+ @Override
+ public List getSessionStateChangesList() {
+ return this.sessionStateChanges;
+ }
+
+ public NativeServerSessionStateChanges() {
+ }
+
+ public NativeServerSessionStateChanges init(NativePacketPayload buf, String encoding) {
+ int totalLen = (int) buf.readInteger(IntegerDataType.INT_LENENC);
+ int start = buf.getPosition();
+ int end = start + totalLen;
+ while (totalLen > 0 && end > start) {
+ int type = (int) buf.readInteger(IntegerDataType.INT1);
+ NativePacketPayload b = new NativePacketPayload(buf.readBytes(StringSelfDataType.STRING_LENENC));
+ switch (type) {
+ case SESSION_TRACK_SYSTEM_VARIABLES:
+ this.sessionStateChanges.add(new SessionStateChange(type) //
+ .addValue(b.readString(StringSelfDataType.STRING_LENENC, encoding)) //
+ .addValue(b.readString(StringSelfDataType.STRING_LENENC, encoding)));
+ break;
+ case SESSION_TRACK_SCHEMA:
+ case SESSION_TRACK_TRANSACTION_CHARACTERISTICS:
+ case SESSION_TRACK_TRANSACTION_STATE:
+ this.sessionStateChanges.add(new SessionStateChange(type) //
+ .addValue(b.readString(StringSelfDataType.STRING_LENENC, encoding)));
+ break;
+ case SESSION_TRACK_GTIDS:
+ b.readInteger(IntegerDataType.INT1); // skip the byte reserved for the encoding specification, see WL#6128
+ this.sessionStateChanges.add(new SessionStateChange(type) //
+ .addValue(b.readString(StringSelfDataType.STRING_LENENC, encoding)));
+ break;
+ case SESSION_TRACK_STATE_CHANGE:
+ default:
+ // store the payload as it is
+ this.sessionStateChanges.add(new SessionStateChange(type) //
+ .addValue(b.readString(StringLengthDataType.STRING_FIXED, encoding, b.getPayloadLength())));
+ }
+ start = buf.getPosition();
+ }
+ return this;
+ }
+
+ }
+}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeSocketConnection.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeSocketConnection.java
index cfcd9e9ac..84de83057 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeSocketConnection.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeSocketConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -93,8 +93,12 @@ public void connect(String hostName, int portNumber, PropertySet propSet, Except
@Override
public void performTlsHandshake(ServerSession serverSession) throws SSLParamsException, FeatureNotAvailableException, IOException {
+ performTlsHandshake(serverSession, null);
+ }
- this.mysqlSocket = this.socketFactory.performTlsHandshake(this, serverSession);
+ @Override
+ public void performTlsHandshake(ServerSession serverSession, Log log) throws SSLParamsException, FeatureNotAvailableException, IOException {
+ this.mysqlSocket = this.socketFactory.performTlsHandshake(this, serverSession, log);
this.mysqlInput = new FullReadInputStream(
this.propertySet.getBooleanProperty(PropertyKey.useUnbufferedInput).getValue() ? getMysqlSocket().getInputStream()
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/SimplePacketReader.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/SimplePacketReader.java
index 2c129ee7c..26efed3cf 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/SimplePacketReader.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/SimplePacketReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -49,6 +49,9 @@ public class SimplePacketReader implements MessageReader maxAllowedPacket) {
this.socketConnection = socketConnection;
this.maxAllowedPacket = maxAllowedPacket;
@@ -56,18 +59,30 @@ public SimplePacketReader(SocketConnection socketConnection, RuntimeProperty this.maxAllowedPacket.getValue()) {
throw new CJPacketTooBigException(packetLength, this.maxAllowedPacket.getValue());
}
-
} catch (IOException | CJPacketTooBigException e) {
try {
this.socketConnection.forceClose();
@@ -78,38 +93,52 @@ public NativePacketHeader readHeader() throws IOException {
}
this.readPacketSequence = hdr.getMessageSequence();
-
return hdr;
}
@Override
public NativePacketPayload readMessage(Optional reuse, NativePacketHeader header) throws IOException {
+ if (this.lastMessage == null) {
+ return readMessageLocal(reuse, header);
+ }
+ NativePacketPayload buf = this.lastMessage;
+ this.lastMessage = null;
+ return buf;
+ }
+
+ @Override
+ public NativePacketPayload probeMessage(Optional reuse, NativePacketHeader header) throws IOException {
+ this.lastMessage = readMessageLocal(reuse, header);
+ return this.lastMessage;
+ }
+
+ private NativePacketPayload readMessageLocal(Optional reuse, NativePacketHeader header) throws IOException {
try {
int packetLength = header.getMessageSize();
- NativePacketPayload buf;
+ NativePacketPayload message;
if (reuse.isPresent()) {
- buf = reuse.get();
+ message = reuse.get();
// Set the Buffer to it's original state
- buf.setPosition(0);
+ message.setPosition(0);
// Do we need to re-alloc the byte buffer?
- if (buf.getByteBuffer().length < packetLength) {
+ if (message.getByteBuffer().length < packetLength) {
// Note: We actually check the length of the buffer, rather than getBufLength(), because getBufLength()
// is not necessarily the actual length of the byte array used as the buffer
- buf.setByteBuffer(new byte[packetLength]);
+ message.setByteBuffer(new byte[packetLength]);
}
// Set the new length
- buf.setPayloadLength(packetLength);
+ message.setPayloadLength(packetLength);
} else {
- buf = new NativePacketPayload(new byte[packetLength]);
+ message = new NativePacketPayload(new byte[packetLength]);
}
// Read the data from the server
- int numBytesRead = this.socketConnection.getMysqlInput().readFully(buf.getByteBuffer(), 0, packetLength);
+ int numBytesRead = this.socketConnection.getMysqlInput().readFully(message.getByteBuffer(), 0, packetLength);
if (numBytesRead != packetLength) {
throw new IOException(Messages.getString("PacketReader.1", new Object[] { packetLength, numBytesRead }));
}
- return buf;
+ return message;
} catch (IOException e) {
try {
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TextResultsetReader.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TextResultsetReader.java
index 43e447b7c..d71512747 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TextResultsetReader.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TextResultsetReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -103,7 +103,8 @@ public Resultset read(int maxRows, boolean streamResults, NativePacketPayload re
// check for file request
if (columnCount == NativePacketPayload.NULL_LENGTH) {
String charEncoding = this.protocol.getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue();
- String fileName = resultPacket.readString(StringSelfDataType.STRING_TERM, this.protocol.doesPlatformDbCharsetMatches() ? charEncoding : null);
+ String fileName = resultPacket.readString(StringSelfDataType.STRING_TERM,
+ this.protocol.getServerSession().getCharsetSettings().doesPlatformDbCharsetMatches() ? charEncoding : null);
resultPacket = this.protocol.sendFileToServer(fileName);
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TimeTrackingPacketReader.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TimeTrackingPacketReader.java
index c3baec407..f063d9a8a 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TimeTrackingPacketReader.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TimeTrackingPacketReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -52,6 +52,11 @@ public NativePacketHeader readHeader() throws IOException {
return this.packetReader.readHeader();
}
+ @Override
+ public NativePacketHeader probeHeader() throws IOException {
+ return this.packetReader.probeHeader();
+ }
+
@Override
public NativePacketPayload readMessage(Optional reuse, NativePacketHeader header) throws IOException {
NativePacketPayload buf = this.packetReader.readMessage(reuse, header);
@@ -59,6 +64,13 @@ public NativePacketPayload readMessage(Optional reuse, Nati
return buf;
}
+ @Override
+ public NativePacketPayload probeMessage(Optional reuse, NativePacketHeader header) throws IOException {
+ NativePacketPayload buf = this.packetReader.probeMessage(reuse, header);
+ this.lastPacketReceivedTimeMs = System.currentTimeMillis();
+ return buf;
+ }
+
@Override
public long getLastPacketReceivedTime() {
return this.lastPacketReceivedTimeMs;
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TracingPacketReader.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TracingPacketReader.java
index 785150529..980148c82 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TracingPacketReader.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/TracingPacketReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -55,8 +55,15 @@ public TracingPacketReader(MessageReader reuse, NativePacketHeader header) throws IOException {
- int packetLength = header.getMessageSize();
- NativePacketPayload buf = this.packetReader.readMessage(reuse, header);
+ return traceMessage(this.packetReader.readMessage(reuse, header), header.getMessageSize(), reuse.isPresent());
+ }
+
+ @Override
+ public NativePacketPayload probeMessage(Optional reuse, NativePacketHeader header) throws IOException {
+ return traceMessage(this.packetReader.probeMessage(reuse, header), header.getMessageSize(), reuse.isPresent());
+ }
+ private NativePacketPayload traceMessage(NativePacketPayload buf, int packetLength, boolean reuse) throws IOException {
StringBuilder traceMessageBuf = new StringBuilder();
- traceMessageBuf.append(Messages.getString(reuse.isPresent() ? "PacketReader.5" : "PacketReader.6"));
+ traceMessageBuf.append(Messages.getString(reuse ? "PacketReader.5" : "PacketReader.6"));
traceMessageBuf.append(StringUtils.dumpAsHex(buf.getByteBuffer(), packetLength < MAX_PACKET_DUMP_LENGTH ? packetLength : MAX_PACKET_DUMP_LENGTH));
if (packetLength > MAX_PACKET_DUMP_LENGTH) {
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/ValueEncoder.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/ValueEncoder.java
new file mode 100644
index 000000000..ce9dc9299
--- /dev/null
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/ValueEncoder.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is also distributed with certain software (including but not
+ * limited to OpenSSL) that is licensed under separate terms, as designated in a
+ * particular file or component or in included license documentation. The
+ * authors of MySQL hereby grant you an additional permission to link the
+ * program and your derivative works with the separately licensed software that
+ * they have included with MySQL.
+ *
+ * Without limiting anything contained in the foregoing, this file, which is
+ * part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
+ * version 1.0, a copy of which can be found at
+ * http://oss.oracle.com/licenses/universal-foss-exception.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package com.mysql.cj.protocol.a;
+
+import static com.mysql.cj.util.StringUtils.getBytes;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+import com.mysql.cj.Messages;
+import com.mysql.cj.MysqlType;
+import com.mysql.cj.exceptions.ExceptionFactory;
+import com.mysql.cj.exceptions.WrongArgumentException;
+import com.mysql.cj.protocol.InternalDate;
+import com.mysql.cj.protocol.InternalTime;
+import com.mysql.cj.protocol.InternalTimestamp;
+import com.mysql.cj.protocol.a.NativeConstants.IntegerDataType;
+import com.mysql.cj.protocol.a.NativeConstants.StringSelfDataType;
+
+public class ValueEncoder {
+ private NativePacketPayload packet;
+ private String characterEncoding;
+ private TimeZone timezone;
+
+ public ValueEncoder(NativePacketPayload packet, String characterEncoding, TimeZone timezone) {
+ this.packet = packet;
+ this.characterEncoding = characterEncoding;
+ this.timezone = timezone;
+ }
+
+ public void encodeValue(Object value, int fieldType) {
+ if (value == null) {
+ return;
+ }
+ switch (fieldType) {
+ case MysqlType.FIELD_TYPE_TINY:
+ encodeInt1(asByte(value));
+ return;
+ case MysqlType.FIELD_TYPE_SHORT:
+ encodeInt2(asShort(value));
+ return;
+ case MysqlType.FIELD_TYPE_LONG:
+ case MysqlType.FIELD_TYPE_FLOAT:
+ encodeInt4(asInteger(value));
+ return;
+ case MysqlType.FIELD_TYPE_LONGLONG:
+ case MysqlType.FIELD_TYPE_DOUBLE:
+ encodeInt8(asLong(value));
+ return;
+ case MysqlType.FIELD_TYPE_DATE:
+ encodeDate(asInternalDate(value));
+ return;
+ case MysqlType.FIELD_TYPE_TIME:
+ encodeTime(asInternalTime(value));
+ return;
+ case MysqlType.FIELD_TYPE_DATETIME:
+ encodeDateTime(asInternalTimestampNoTz(value));
+ return;
+ case MysqlType.FIELD_TYPE_TIMESTAMP:
+ encodeTimeStamp(asInternalTimestampTz(value));
+ return;
+ case MysqlType.FIELD_TYPE_STRING:
+ encodeString(asString(value));
+ return;
+ }
+ }
+
+ public void encodeInt1(Byte value) {
+ this.packet.writeInteger(IntegerDataType.INT1, value.longValue());
+ }
+
+ public void encodeInt2(Short value) {
+ this.packet.writeInteger(IntegerDataType.INT2, value.longValue());
+ }
+
+ public void encodeInt4(Integer value) {
+ this.packet.writeInteger(IntegerDataType.INT4, value.longValue());
+ }
+
+ public void encodeInt8(Long value) {
+ this.packet.writeInteger(IntegerDataType.INT8, value.longValue());
+ }
+
+ public void encodeDate(InternalDate date) {
+ this.packet.ensureCapacity(NativeConstants.BIN_LEN_DATE + 1);
+ this.packet.writeInteger(IntegerDataType.INT1, NativeConstants.BIN_LEN_DATE);
+ this.packet.writeInteger(IntegerDataType.INT2, date.getYear());
+ this.packet.writeInteger(IntegerDataType.INT1, date.getMonth());
+ this.packet.writeInteger(IntegerDataType.INT1, date.getDay());
+ }
+
+ public void encodeTime(InternalTime time) {
+ boolean hasFractionalSeconds = time.getNanos() > 0;
+ this.packet.ensureCapacity((hasFractionalSeconds ? NativeConstants.BIN_LEN_TIME_WITH_MICROS : NativeConstants.BIN_LEN_TIME_NO_FRAC) + 1);
+ this.packet.writeInteger(IntegerDataType.INT1, hasFractionalSeconds ? NativeConstants.BIN_LEN_TIME_WITH_MICROS : NativeConstants.BIN_LEN_TIME_NO_FRAC);
+ this.packet.writeInteger(IntegerDataType.INT1, time.isNegative() ? 1 : 0);
+ this.packet.writeInteger(IntegerDataType.INT4, time.getHours() / 24);
+ this.packet.writeInteger(IntegerDataType.INT1, time.getHours() % 24);
+ this.packet.writeInteger(IntegerDataType.INT1, time.getMinutes());
+ this.packet.writeInteger(IntegerDataType.INT1, time.getSeconds());
+ if (hasFractionalSeconds) {
+ this.packet.writeInteger(IntegerDataType.INT4, TimeUnit.NANOSECONDS.toMicros(time.getNanos()));
+ }
+ }
+
+ public void encodeDateTime(InternalTimestamp timestamp) {
+ boolean hasFractionalSeconds = timestamp.getNanos() > 0;
+ this.packet.ensureCapacity((hasFractionalSeconds ? NativeConstants.BIN_LEN_TIMESTAMP_WITH_MICROS : NativeConstants.BIN_LEN_TIMESTAMP_NO_FRAC) + 1);
+ this.packet.writeInteger(IntegerDataType.INT1,
+ hasFractionalSeconds ? NativeConstants.BIN_LEN_TIMESTAMP_WITH_MICROS : NativeConstants.BIN_LEN_TIMESTAMP_NO_FRAC); // length
+ this.packet.writeInteger(IntegerDataType.INT2, timestamp.getYear());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getMonth());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getDay());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getHours());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getMinutes());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getSeconds());
+ if (hasFractionalSeconds) {
+ this.packet.writeInteger(IntegerDataType.INT4, TimeUnit.NANOSECONDS.toMicros(timestamp.getNanos()));
+ }
+ }
+
+ public void encodeTimeStamp(InternalTimestamp timestamp) {
+ this.packet.ensureCapacity(NativeConstants.BIN_LEN_TIMESTAMP_WITH_TZ + 1);
+ this.packet.writeInteger(IntegerDataType.INT1, NativeConstants.BIN_LEN_TIMESTAMP_WITH_TZ);
+ this.packet.writeInteger(IntegerDataType.INT2, timestamp.getYear());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getMonth());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getDay());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getHours());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getMinutes());
+ this.packet.writeInteger(IntegerDataType.INT1, timestamp.getSeconds());
+ this.packet.writeInteger(IntegerDataType.INT4, TimeUnit.NANOSECONDS.toMicros(timestamp.getNanos()));
+ this.packet.writeInteger(IntegerDataType.INT2, timestamp.getOffset());
+ }
+
+ public void encodeString(String value) {
+ this.packet.writeBytes(StringSelfDataType.STRING_LENENC, getBytes(value, this.characterEncoding));
+ }
+
+ private Byte asByte(Object value) {
+ if (Boolean.class.isInstance(value)) {
+ return (Boolean) value ? new Byte((byte) 1) : new Byte((byte) 0);
+ }
+
+ if (Byte.class.isInstance(value)) {
+ return (Byte) value;
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongTinyIntValueType", new Object[] { value.getClass() }));
+ }
+
+ private Short asShort(Object value) {
+ if (Short.class.isInstance(value)) {
+ return (Short) value;
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongSmallIntValueType", new Object[] { value.getClass() }));
+ }
+
+ private Integer asInteger(Object value) {
+ if (Integer.class.isInstance(value)) {
+ return (Integer) value;
+ }
+
+ if (Float.class.isInstance(value)) {
+ return Float.floatToIntBits((Float) value);
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongIntValueType", new Object[] { value.getClass() }));
+ }
+
+ private Long asLong(Object value) {
+ if (Long.class.isInstance(value)) {
+ return (Long) value;
+ }
+
+ if (Double.class.isInstance(value)) {
+ return Double.doubleToLongBits((Double) value);
+ }
+
+ if (BigInteger.class.isInstance(value)) {
+ return ((BigInteger) value).longValue();
+ }
+
+ if (BigDecimal.class.isInstance(value)) {
+ return Double.doubleToLongBits(((BigDecimal) value).doubleValue());
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongBigIntValueType", new Object[] { value.getClass() }));
+ }
+
+ private InternalDate asInternalDate(Object value) {
+ if (LocalDate.class.isInstance(value)) {
+ LocalDate localDate = (LocalDate) value;
+
+ InternalDate internalDate = new InternalDate();
+ internalDate.setYear(localDate.getYear());
+ internalDate.setMonth(localDate.getMonthValue());
+ internalDate.setDay(localDate.getDayOfMonth());
+ return internalDate;
+ }
+
+ if (Date.class.isInstance(value)) {
+ Calendar calendar = Calendar.getInstance(this.timezone);
+ calendar.setTime((Date) value);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+
+ InternalDate internalDate = new InternalDate();
+ internalDate.setYear(calendar.get(Calendar.YEAR));
+ internalDate.setMonth(calendar.get(Calendar.MONTH) + 1);
+ internalDate.setDay(calendar.get(Calendar.DAY_OF_MONTH));
+ return internalDate;
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongDateValueType", new Object[] { value.getClass() }));
+ }
+
+ private InternalTime asInternalTime(Object value) {
+ if (LocalTime.class.isInstance(value)) {
+ LocalTime localTime = (LocalTime) value;
+
+ InternalTime internalTime = new InternalTime();
+ internalTime.setHours(localTime.getHour());
+ internalTime.setMinutes(localTime.getMinute());
+ internalTime.setSeconds(localTime.getSecond());
+ internalTime.setNanos(localTime.getNano());
+ return internalTime;
+ }
+
+ if (OffsetTime.class.isInstance(value)) {
+ OffsetTime offsetTime = (OffsetTime) value;
+
+ InternalTime internalTime = new InternalTime();
+ internalTime.setHours(offsetTime.getHour());
+ internalTime.setMinutes(offsetTime.getMinute());
+ internalTime.setSeconds(offsetTime.getSecond());
+ internalTime.setNanos(offsetTime.getNano());
+
+ return internalTime;
+ }
+
+ if (Duration.class.isInstance(value)) {
+ Duration duration = (Duration) value;
+ Duration durationAbs = duration.abs();
+
+ long fullSeconds = durationAbs.getSeconds();
+ int seconds = (int) (fullSeconds % 60);
+ long fullMinutes = fullSeconds / 60;
+ int minutes = (int) (fullMinutes % 60);
+ long fullHours = fullMinutes / 60;
+
+ InternalTime internalTime = new InternalTime();
+ internalTime.setNegative(duration.isNegative());
+ internalTime.setHours((int) fullHours);
+ internalTime.setMinutes(minutes);
+ internalTime.setSeconds(seconds);
+ internalTime.setNanos(durationAbs.getNano());
+ return internalTime;
+ }
+
+ if (Time.class.isInstance(value)) {
+ Time time = (Time) value;
+
+ Calendar calendar = Calendar.getInstance(this.timezone);
+ calendar.setTime(time);
+
+ InternalTime internalTime = new InternalTime();
+ internalTime.setHours(calendar.get(Calendar.HOUR_OF_DAY));
+ internalTime.setMinutes(calendar.get(Calendar.MINUTE));
+ internalTime.setSeconds(calendar.get(Calendar.SECOND));
+ internalTime.setNanos((int) TimeUnit.MILLISECONDS.toNanos(calendar.get(Calendar.MILLISECOND)));
+ return internalTime;
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongTimeValueType", new Object[] { value.getClass() }));
+ }
+
+ private InternalTimestamp asInternalTimestampNoTz(Object value) {
+ if (LocalDateTime.class.isInstance(value)) {
+ LocalDateTime localDateTime = (LocalDateTime) value;
+
+ InternalTimestamp internalTimestamp = new InternalTimestamp();
+ internalTimestamp.setYear(localDateTime.getYear());
+ internalTimestamp.setMonth(localDateTime.getMonthValue());
+ internalTimestamp.setDay(localDateTime.getDayOfMonth());
+ internalTimestamp.setHours(localDateTime.getHour());
+ internalTimestamp.setMinutes(localDateTime.getMinute());
+ internalTimestamp.setSeconds(localDateTime.getSecond());
+ internalTimestamp.setNanos(localDateTime.getNano());
+ return internalTimestamp;
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongDatetimeValueType", new Object[] { value.getClass() }));
+ }
+
+ private InternalTimestamp asInternalTimestampTz(Object value) {
+ if (Instant.class.isInstance(value)) {
+ Instant instant = (Instant) value;
+ OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC);
+
+ InternalTimestamp internalTimestamp = new InternalTimestamp();
+ internalTimestamp.setYear(offsetDateTime.getYear());
+ internalTimestamp.setMonth(offsetDateTime.getMonthValue());
+ internalTimestamp.setDay(offsetDateTime.getDayOfMonth());
+ internalTimestamp.setHours(offsetDateTime.getHour());
+ internalTimestamp.setMinutes(offsetDateTime.getMinute());
+ internalTimestamp.setSeconds(offsetDateTime.getSecond());
+ internalTimestamp.setNanos(offsetDateTime.getNano());
+ internalTimestamp.setOffset(0); // UTC
+ return internalTimestamp;
+ }
+
+ if (OffsetDateTime.class.isInstance(value)) {
+ OffsetDateTime offsetDateTime = (OffsetDateTime) value;
+
+ InternalTimestamp internalTimestamp = new InternalTimestamp();
+ internalTimestamp.setYear(offsetDateTime.getYear());
+ internalTimestamp.setMonth(offsetDateTime.getMonthValue());
+ internalTimestamp.setDay(offsetDateTime.getDayOfMonth());
+ internalTimestamp.setHours(offsetDateTime.getHour());
+ internalTimestamp.setMinutes(offsetDateTime.getMinute());
+ internalTimestamp.setSeconds(offsetDateTime.getSecond());
+ internalTimestamp.setNanos(offsetDateTime.getNano());
+ internalTimestamp.setOffset((int) TimeUnit.SECONDS.toMinutes(offsetDateTime.getOffset().getTotalSeconds()));
+ return internalTimestamp;
+ }
+
+ if (ZonedDateTime.class.isInstance(value)) {
+ ZonedDateTime zonedDateTime = (ZonedDateTime) value;
+
+ InternalTimestamp internalTimestamp = new InternalTimestamp();
+ internalTimestamp.setYear(zonedDateTime.getYear());
+ internalTimestamp.setMonth(zonedDateTime.getMonthValue());
+ internalTimestamp.setDay(zonedDateTime.getDayOfMonth());
+ internalTimestamp.setHours(zonedDateTime.getHour());
+ internalTimestamp.setMinutes(zonedDateTime.getMinute());
+ internalTimestamp.setSeconds(zonedDateTime.getSecond());
+ internalTimestamp.setNanos(zonedDateTime.getNano());
+ internalTimestamp.setOffset((int) TimeUnit.SECONDS.toMinutes(zonedDateTime.getOffset().getTotalSeconds()));
+ return internalTimestamp;
+
+ }
+
+ if (Calendar.class.isInstance(value)) {
+ Calendar calendar = (Calendar) value;
+
+ InternalTimestamp internalTimestamp = new InternalTimestamp();
+ internalTimestamp.setYear(calendar.get(Calendar.YEAR));
+ internalTimestamp.setMonth(calendar.get(Calendar.MONTH) + 1);
+ internalTimestamp.setDay(calendar.get(Calendar.DAY_OF_MONTH));
+ internalTimestamp.setHours(calendar.get(Calendar.HOUR_OF_DAY));
+ internalTimestamp.setMinutes(calendar.get(Calendar.MINUTE));
+ internalTimestamp.setSeconds(calendar.get(Calendar.SECOND));
+ internalTimestamp.setNanos((int) TimeUnit.MILLISECONDS.toNanos(calendar.get(Calendar.MILLISECOND)));
+ internalTimestamp.setOffset((int) TimeUnit.MILLISECONDS.toMinutes(calendar.getTimeZone().getOffset(calendar.getTimeInMillis())));
+ return internalTimestamp;
+
+ }
+
+ if (Timestamp.class.isInstance(value)) { // must be checked before java.util.Date.
+ Timestamp timestamp = (Timestamp) value;
+
+ Calendar calendar = Calendar.getInstance(this.timezone);
+ calendar.setTime(timestamp);
+
+ InternalTimestamp internalTimestamp = new InternalTimestamp();
+ internalTimestamp.setYear(calendar.get(Calendar.YEAR));
+ internalTimestamp.setMonth(calendar.get(Calendar.MONTH) + 1);
+ internalTimestamp.setDay(calendar.get(Calendar.DAY_OF_MONTH));
+ internalTimestamp.setHours(calendar.get(Calendar.HOUR_OF_DAY));
+ internalTimestamp.setMinutes(calendar.get(Calendar.MINUTE));
+ internalTimestamp.setSeconds(calendar.get(Calendar.SECOND));
+ internalTimestamp.setNanos(timestamp.getNanos());
+ internalTimestamp.setOffset((int) TimeUnit.MILLISECONDS.toMinutes(calendar.getTimeZone().getOffset(calendar.getTimeInMillis())));
+ return internalTimestamp;
+ }
+
+ if (java.util.Date.class.isInstance(value)) {
+ java.util.Date date = (java.util.Date) value;
+
+ Calendar calendar = Calendar.getInstance(this.timezone);
+ calendar.setTime(date);
+
+ InternalTimestamp internalTimestamp = new InternalTimestamp();
+ internalTimestamp.setYear(calendar.get(Calendar.YEAR));
+ internalTimestamp.setMonth(calendar.get(Calendar.MONTH) + 1);
+ internalTimestamp.setDay(calendar.get(Calendar.DAY_OF_MONTH));
+ internalTimestamp.setHours(calendar.get(Calendar.HOUR_OF_DAY));
+ internalTimestamp.setMinutes(calendar.get(Calendar.MINUTE));
+ internalTimestamp.setSeconds(calendar.get(Calendar.SECOND));
+ internalTimestamp.setNanos((int) TimeUnit.MILLISECONDS.toNanos(calendar.get(Calendar.MILLISECOND)));
+ internalTimestamp.setOffset((int) TimeUnit.MILLISECONDS.toMinutes(calendar.getTimeZone().getOffset(date.getTime())));
+ return internalTimestamp;
+ }
+
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ValueEncoder.WrongTimestampValueType", new Object[] { value.getClass() }));
+ }
+
+ private String asString(Object value) {
+ if (String.class.isInstance(value)) {
+ return (String) value;
+ }
+
+ return value.toString();
+ }
+}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationKerberosClient.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationKerberosClient.java
new file mode 100644
index 000000000..c8ad00ba0
--- /dev/null
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationKerberosClient.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is also distributed with certain software (including but not
+ * limited to OpenSSL) that is licensed under separate terms, as designated in a
+ * particular file or component or in included license documentation. The
+ * authors of MySQL hereby grant you an additional permission to link the
+ * program and your derivative works with the separately licensed software that
+ * they have included with MySQL.
+ *
+ * Without limiting anything contained in the foregoing, this file, which is
+ * part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
+ * version 1.0, a copy of which can be found at
+ * http://oss.oracle.com/licenses/universal-foss-exception.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package com.mysql.cj.protocol.a.authentication;
+
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import com.mysql.cj.Messages;
+import com.mysql.cj.callback.MysqlCallbackHandler;
+import com.mysql.cj.callback.UsernameCallback;
+import com.mysql.cj.exceptions.CJException;
+import com.mysql.cj.exceptions.ExceptionFactory;
+import com.mysql.cj.protocol.AuthenticationPlugin;
+import com.mysql.cj.protocol.Protocol;
+import com.mysql.cj.protocol.a.NativeConstants.IntegerDataType;
+import com.mysql.cj.protocol.a.NativeConstants.StringLengthDataType;
+import com.mysql.cj.protocol.a.NativeConstants.StringSelfDataType;
+import com.mysql.cj.protocol.a.NativePacketPayload;
+import com.mysql.cj.util.StringUtils;
+
+/**
+ * MySQL 'authentication_kerberos_client' authentication plugin.
+ */
+public class AuthenticationKerberosClient implements AuthenticationPlugin {
+ public static String PLUGIN_NAME = "authentication_kerberos_client";
+
+ private static final String LOGIN_CONFIG_ENTRY = "MySQLConnectorJ";
+ private static final String AUTHENTICATION_MECHANISM = "GSSAPI";
+
+ private String sourceOfAuthData = PLUGIN_NAME;
+
+ private MysqlCallbackHandler usernameCallbackHandler = null;
+ private String user = null;
+ private String password = null;
+ private String userPrincipalName = null;
+
+ private Subject subject = null;
+ private String cachedPrincipalName = null;
+
+ private CallbackHandler credentialsCallbackHandler = (cbs) -> {
+ for (Callback cb : cbs) {
+ if (NameCallback.class.isAssignableFrom(cb.getClass())) {
+ ((NameCallback) cb).setName(this.userPrincipalName);
+ } else if (PasswordCallback.class.isAssignableFrom(cb.getClass())) {
+ ((PasswordCallback) cb).setPassword(this.password == null ? new char[0] : this.password.toCharArray());
+ } else {
+ throw new UnsupportedCallbackException(cb, cb.getClass().getName());
+ }
+ }
+ };
+
+ private SaslClient saslClient = null;
+
+ @Override
+ public void init(Protocol prot, MysqlCallbackHandler cbh) {
+ this.usernameCallbackHandler = cbh;
+ }
+
+ @Override
+ public void reset() {
+ if (this.saslClient != null) {
+ try {
+ this.saslClient.dispose();
+ } catch (SaslException e) {
+ // Ignore exception.
+ }
+ }
+ this.user = null;
+ this.password = null;
+ this.saslClient = null;
+ }
+
+ @Override
+ public void destroy() {
+ reset();
+ this.userPrincipalName = null;
+ this.subject = null;
+ this.cachedPrincipalName = null;
+ }
+
+ @Override
+ public String getProtocolPluginName() {
+ return PLUGIN_NAME;
+ }
+
+ @Override
+ public boolean requiresConfidentiality() {
+ return false;
+ }
+
+ @Override
+ public boolean isReusable() {
+ return false;
+ }
+
+ @Override
+ public void setAuthenticationParameters(String user, String password) {
+ this.user = user;
+ this.password = password;
+
+ if (this.user == null) {
+ try {
+ // Try to obtain the user name from a cached TGT.
+ initializeAuthentication();
+ int pos = this.cachedPrincipalName.indexOf('@');
+ if (pos >= 0) {
+ this.user = this.cachedPrincipalName.substring(0, pos);
+ } else {
+ this.user = this.cachedPrincipalName;
+ }
+ } catch (CJException e) {
+ // Fall-back to system login user.
+ this.user = System.getProperty("user.name");
+ }
+ if (this.usernameCallbackHandler != null) {
+ this.usernameCallbackHandler.handle(new UsernameCallback(this.user));
+ }
+ }
+ }
+
+ @Override
+ public void setSourceOfAuthData(String sourceOfAuthData) {
+ this.sourceOfAuthData = sourceOfAuthData;
+ }
+
+ @Override
+ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List toServer) {
+ toServer.clear();
+
+ if (!this.sourceOfAuthData.equals(PLUGIN_NAME) || fromServer.getPayloadLength() == 0) {
+ // Cannot do anything with whatever payload comes from the server, so just skip this iteration and wait for a Protocol::AuthSwitchRequest or a
+ // Protocol::AuthNextFactor.
+ return true;
+ }
+
+ if (this.saslClient == null) {
+ try {
+ // Protocol::AuthSwitchRequest plugin data contains:
+ // int<2> SPN string length
+ // string SPN string
+ // int<2> User Principal Name realm string length
+ // string User Principal Name realm string
+ int servicePrincipalNameLength = (int) fromServer.readInteger(IntegerDataType.INT2);
+ String servicePrincipalName = fromServer.readString(StringLengthDataType.STRING_VAR, "ASCII", servicePrincipalNameLength);
+ // A typical Kerberos V5 principal has the structure "primary/instance@REALM".
+ String primary = "";
+ String instance = "";
+ // Being a bit lenient here: the spec allows escaping characters (https://tools.ietf.org/html/rfc1964#section-2.1.1).
+ int posAt = servicePrincipalName.indexOf('@');
+ if (posAt < 0) {
+ posAt = servicePrincipalName.length();
+ }
+ int posSlash = servicePrincipalName.lastIndexOf('/', posAt);
+ if (posSlash >= 0) {
+ primary = servicePrincipalName.substring(0, posSlash);
+ instance = servicePrincipalName.substring(posSlash + 1, posAt);
+ } else {
+ primary = servicePrincipalName.substring(0, posAt);
+ }
+
+ int userPrincipalRealmLength = (int) fromServer.readInteger(IntegerDataType.INT2);
+ String userPrincipalRealm = fromServer.readString(StringLengthDataType.STRING_VAR, "ASCII", userPrincipalRealmLength);
+ this.userPrincipalName = this.user + "@" + userPrincipalRealm;
+
+ initializeAuthentication();
+
+ // Create a GSSAPI SASL client using the credentials stored in this thread's Subject.
+ try {
+ final String localPrimary = primary;
+ final String localInstance = instance;
+ this.saslClient = Subject.doAs(this.subject, (PrivilegedExceptionAction) () -> Sasl
+ .createSaslClient(new String[] { AUTHENTICATION_MECHANISM }, null, localPrimary, localInstance, null, null));
+ } catch (PrivilegedActionException e) {
+ // SaslException is the only checked exception that can be thrown.
+ throw (SaslException) e.getException();
+ }
+
+ } catch (SaslException e) {
+ throw ExceptionFactory.createException(
+ Messages.getString("AuthenticationKerberosClientPlugin.FailCreateSaslClient", new Object[] { AUTHENTICATION_MECHANISM }), e);
+ }
+
+ if (this.saslClient == null) {
+ throw ExceptionFactory.createException(
+ Messages.getString("AuthenticationKerberosClientPlugin.FailCreateSaslClient", new Object[] { AUTHENTICATION_MECHANISM }));
+ }
+ }
+
+ if (!this.saslClient.isComplete()) {
+ // All packets: send payload to the SASL client.
+ try {
+ Subject.doAs(this.subject, (PrivilegedExceptionAction) () -> {
+ byte[] response = this.saslClient.evaluateChallenge(fromServer.readBytes(StringSelfDataType.STRING_EOF));
+ if (response != null) {
+ NativePacketPayload bresp = new NativePacketPayload(response);
+ bresp.setPosition(0);
+ toServer.add(bresp);
+ }
+ return null;
+ });
+ } catch (PrivilegedActionException e) {
+ throw ExceptionFactory.createException(
+ Messages.getString("AuthenticationKerberosClientPlugin.ErrProcessingAuthIter", new Object[] { AUTHENTICATION_MECHANISM }),
+ e.getException());
+ }
+ }
+ return true;
+ }
+
+ private void initializeAuthentication() {
+ if (this.subject != null && this.cachedPrincipalName != null && this.cachedPrincipalName.equals(this.userPrincipalName)) {
+ // Already initialized with the right user.
+ return;
+ }
+
+ // In-memory login configuration. Used only if system property 'java.security.auth.login.config' is not set.
+ String loginConfigFile = System.getProperty("java.security.auth.login.config");
+ Configuration loginConfig = null;
+ if (StringUtils.isNullOrEmpty(loginConfigFile)) {
+ final String localUser = this.userPrincipalName;
+ final boolean debug = Boolean.getBoolean("sun.security.jgss.debug");
+ loginConfig = new Configuration() {
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map options = new HashMap<>();
+ options.put("useTicketCache", "true");
+ options.put("renewTGT", "false");
+ if (localUser != null) {
+ options.put("principal", localUser);
+ }
+ options.put("debug", Boolean.toString(debug)); // Hook debugging on system property 'sun.security.jgss.debug'.
+ return new AppConfigurationEntry[] { new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options) };
+ }
+ };
+ }
+
+ // Login into Kerberos service and obtain the user subject/credentials.
+ LoginContext loginContext;
+ try {
+ loginContext = new LoginContext(LOGIN_CONFIG_ENTRY, null, this.credentialsCallbackHandler, loginConfig);
+ loginContext.login();
+ this.subject = loginContext.getSubject();
+ this.cachedPrincipalName = this.subject.getPrincipals().iterator().next().getName();
+ } catch (LoginException e) {
+ throw ExceptionFactory.createException(Messages.getString("AuthenticationKerberosClientPlugin.FailAuthenticateUser"), e);
+ }
+ }
+}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationLdapSaslClientPlugin.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationLdapSaslClientPlugin.java
index 89f14582d..046f41960 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationLdapSaslClientPlugin.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationLdapSaslClientPlugin.java
@@ -52,6 +52,8 @@
import javax.security.sasl.SaslException;
import com.mysql.cj.Messages;
+import com.mysql.cj.callback.MysqlCallbackHandler;
+import com.mysql.cj.callback.UsernameCallback;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.exceptions.CJException;
import com.mysql.cj.exceptions.ExceptionFactory;
@@ -78,8 +80,8 @@ private enum AuthenticationMechanisms {
SCRAM_SHA_256(ScramSha256SaslClient.IANA_MECHANISM_NAME, ScramSha256SaslClient.MECHANISM_NAME), //
GSSAPI("GSSAPI", "GSSAPI");
- private String mechName;
- private String saslServiceName;
+ private String mechName = null;
+ private String saslServiceName = null;
private AuthenticationMechanisms(String mechName, String serviceName) {
this.mechName = mechName;
@@ -105,11 +107,12 @@ String getSaslServiceName() {
}
private Protocol> protocol = null;
- private String user;
- private String password;
+ private MysqlCallbackHandler usernameCallbackHandler = null;
+ private String user = null;
+ private String password = null;
- private AuthenticationMechanisms authMech;
- private SaslClient saslClient;
+ private AuthenticationMechanisms authMech = null;
+ private SaslClient saslClient = null;
private Subject subject = null;
private boolean firstPass = true;
@@ -135,6 +138,12 @@ public void init(Protocol prot) {
Security.addProvider(new ScramShaSaslProvider());
}
+ @Override
+ public void init(Protocol prot, MysqlCallbackHandler cbh) {
+ init(prot);
+ this.usernameCallbackHandler = cbh;
+ }
+
@Override
public void reset() {
if (this.saslClient != null) {
@@ -177,6 +186,14 @@ public boolean isReusable() {
public void setAuthenticationParameters(String user, String password) {
this.user = user;
this.password = password;
+
+ if (this.user == null) {
+ // Fall-back to system login user.
+ this.user = System.getProperty("user.name");
+ if (this.usernameCallbackHandler != null) {
+ this.usernameCallbackHandler.handle(new UsernameCallback(this.user));
+ }
+ }
}
@Override
@@ -192,8 +209,7 @@ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List {
+ public static String PLUGIN_NAME = "authentication_oci_client";
+
+ private String sourceOfAuthData = PLUGIN_NAME;
+
+ protected Protocol protocol = null;
+ private MysqlCallbackHandler usernameCallbackHandler = null;
+ private String fingerprint = null;
+ private RSAPrivateKey privateKey = null;
+
+ @Override
+ public void init(Protocol prot, MysqlCallbackHandler cbh) {
+ this.protocol = prot;
+ this.usernameCallbackHandler = cbh;
+ }
+
+ @Override
+ public void reset() {
+ this.fingerprint = null;
+ this.privateKey = null;
+ }
+
+ @Override
+ public void destroy() {
+ reset();
+ }
+
+ @Override
+ public String getProtocolPluginName() {
+ return PLUGIN_NAME;
+ }
+
+ @Override
+ public boolean requiresConfidentiality() {
+ return false;
+ }
+
+ @Override
+ public boolean isReusable() {
+ return false;
+ }
+
+ @Override
+ public void setAuthenticationParameters(String user, String password) {
+ if (user == null && this.usernameCallbackHandler != null) {
+ // Fall-back to system login user.
+ this.usernameCallbackHandler.handle(new UsernameCallback(System.getProperty("user.name")));
+ }
+ }
+
+ @Override
+ public void setSourceOfAuthData(String sourceOfAuthData) {
+ this.sourceOfAuthData = sourceOfAuthData;
+ }
+
+ @Override
+ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List toServer) {
+ toServer.clear();
+
+ if (!this.sourceOfAuthData.equals(PLUGIN_NAME) || fromServer.getPayloadLength() == 0) {
+ // Cannot do anything with whatever payload comes from the server, so just skip this iteration and wait for a Protocol::AuthSwitchRequest or a
+ // Protocol::AuthNextFactor.
+ toServer.add(new NativePacketPayload(0));
+ return true;
+ }
+
+ initializePrivateKey();
+
+ byte[] nonce = fromServer.readBytes(StringSelfDataType.STRING_EOF);
+ byte[] signature = ExportControlled.sign(nonce, this.privateKey);
+ if (signature == null) {
+ signature = new byte[0];
+ }
+ String payload = String.format("{\"fingerprint\":\"%s\", \"signature\":\"%s\"}", this.fingerprint, Base64.getEncoder().encodeToString(signature));
+ toServer.add(new NativePacketPayload(payload.getBytes(Charset.defaultCharset())));
+ return true;
+ }
+
+ private void initializePrivateKey() {
+ if (this.privateKey != null) {
+ // Already initialized.
+ return;
+ }
+
+ ConfigFile configFile;
+ try {
+ String configFilePath = this.protocol.getPropertySet().getStringProperty(PropertyKey.ociConfigFile.getKeyName()).getStringValue();
+ if (StringUtils.isNullOrEmpty(configFilePath)) {
+ configFile = ConfigFileReader.parseDefault();
+ } else if (Files.exists(Paths.get(configFilePath))) {
+ configFile = ConfigFileReader.parse(configFilePath);
+ } else {
+ throw ExceptionFactory.createException("configuration file does not exist");
+ }
+ } catch (NoClassDefFoundError e) {
+ throw ExceptionFactory.createException(Messages.getString("AuthenticationOciClientPlugin.SdkNotFound"), e);
+ } catch (IOException e) {
+ throw ExceptionFactory.createException(Messages.getString("AuthenticationOciClientPlugin.OciConfigFileError"), e);
+ }
+ this.fingerprint = configFile.get("fingerprint");
+ if (StringUtils.isNullOrEmpty(this.fingerprint)) {
+ throw ExceptionFactory.createException(Messages.getString("AuthenticationOciClientPlugin.OciConfigFileMissingEntry"));
+ }
+ String keyFilePath = configFile.get("key_file");
+ if (StringUtils.isNullOrEmpty(keyFilePath)) {
+ throw ExceptionFactory.createException(Messages.getString("AuthenticationOciClientPlugin.OciConfigFileMissingEntry"));
+ }
+
+ try {
+ String key = new String(Files.readAllBytes(Paths.get(keyFilePath)), Charset.defaultCharset());
+ this.privateKey = ExportControlled.decodeRSAPrivateKey(key);
+ } catch (IOException e) {
+ throw ExceptionFactory.createException(Messages.getString("AuthenticationOciClientPlugin.PrivateKeyNotFound"), e);
+ } catch (RSAException | IllegalArgumentException e) {
+ throw ExceptionFactory.createException(Messages.getString("AuthenticationOciClientPlugin.PrivateKeyNotValid"), e);
+ }
+ }
+}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/CachingSha2PasswordPlugin.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/CachingSha2PasswordPlugin.java
index 9e1947f99..ba94b5759 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/CachingSha2PasswordPlugin.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/CachingSha2PasswordPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2017, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -91,8 +91,9 @@ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List NativeConstants.SEED_LENGTH) {
+ if (this.publicKeyRequested && fromServer.getPayloadLength() > NativeConstants.SEED_LENGTH + 1) { // auth data is null terminated
// Servers affected by Bug#70865 could send Auth Switch instead of key after Public Key Retrieval,
// so we check payload length to detect that.
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/MysqlClearPasswordPlugin.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/MysqlClearPasswordPlugin.java
index 39cf026d9..6428386e7 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/MysqlClearPasswordPlugin.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/MysqlClearPasswordPlugin.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2012, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -45,8 +45,8 @@
public class MysqlClearPasswordPlugin implements AuthenticationPlugin {
public static String PLUGIN_NAME = "mysql_clear_password";
- private Protocol protocol;
- private MysqlCallbackHandler usernameCallbackHandler;
+ private Protocol protocol = null;
+ private MysqlCallbackHandler usernameCallbackHandler = null;
private String password = null;
@Override
@@ -73,7 +73,7 @@ public boolean isReusable() {
public void setAuthenticationParameters(String user, String password) {
this.password = password;
- if (user == null) {
+ if (user == null && this.usernameCallbackHandler != null) {
// Fall-back to system login user.
this.usernameCallbackHandler.handle(new UsernameCallback(System.getProperty("user.name")));
}
@@ -82,7 +82,7 @@ public void setAuthenticationParameters(String user, String password) {
public boolean nextAuthenticationStep(NativePacketPayload fromServer, List toServer) {
toServer.clear();
- String encoding = this.protocol.versionMeetsMinimum(5, 7, 6) ? this.protocol.getPasswordCharacterEncoding() : "UTF-8";
+ String encoding = this.protocol.getServerSession().getCharsetSettings().getPasswordCharacterEncoding();
NativePacketPayload bresp = new NativePacketPayload(StringUtils.getBytes(this.password != null ? this.password : "", encoding));
bresp.setPosition(bresp.getPayloadLength());
@@ -92,5 +92,4 @@ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List {
public static String PLUGIN_NAME = "mysql_native_password";
- private Protocol protocol;
- private MysqlCallbackHandler usernameCallbackHandler;
+ private Protocol protocol = null;
+ private MysqlCallbackHandler usernameCallbackHandler = null;
private String password = null;
@Override
@@ -73,14 +73,13 @@ public boolean isReusable() {
public void setAuthenticationParameters(String user, String password) {
this.password = password;
- if (user == null) {
+ if (user == null && this.usernameCallbackHandler != null) {
// Fall-back to system login user.
this.usernameCallbackHandler.handle(new UsernameCallback(System.getProperty("user.name")));
}
}
public boolean nextAuthenticationStep(NativePacketPayload fromServer, List toServer) {
-
toServer.clear();
NativePacketPayload bresp = null;
@@ -90,12 +89,11 @@ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List {
public static String PLUGIN_NAME = "mysql_old_password";
- private Protocol protocol;
- private MysqlCallbackHandler usernameCallbackHandler;
+ private Protocol protocol = null;
+ private MysqlCallbackHandler usernameCallbackHandler = null;
private String password = null;
@Override
@@ -75,7 +75,7 @@ public boolean isReusable() {
public void setAuthenticationParameters(String user, String password) {
this.password = password;
- if (user == null) {
+ if (user == null && this.usernameCallbackHandler != null) {
// Fall-back to system login user.
this.usernameCallbackHandler.handle(new UsernameCallback(System.getProperty("user.name")));
}
@@ -92,8 +92,8 @@ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List {
public static String PLUGIN_NAME = "sha256_password";
- protected Protocol protocol;
- protected MysqlCallbackHandler usernameCallbackHandler;
+ protected Protocol protocol = null;
+ protected MysqlCallbackHandler usernameCallbackHandler = null;
protected String password = null;
protected String seed = null;
protected boolean publicKeyRequested = false;
@@ -68,9 +68,9 @@ public class Sha256PasswordPlugin implements AuthenticationPlugin serverRSAPublicKeyFile = null;
@Override
- public void init(Protocol prot, MysqlCallbackHandler mch) {
+ public void init(Protocol prot, MysqlCallbackHandler cbh) {
this.protocol = prot;
- this.usernameCallbackHandler = mch;
+ this.usernameCallbackHandler = cbh;
this.serverRSAPublicKeyFile = this.protocol.getPropertySet().getStringProperty(PropertyKey.serverRSAPublicKeyFile);
String pkURL = this.serverRSAPublicKeyFile.getValue();
@@ -99,7 +99,7 @@ public boolean isReusable() {
public void setAuthenticationParameters(String user, String password) {
this.password = password;
- if (user == null) {
+ if (user == null && this.usernameCallbackHandler != null) {
// Fall-back to system login user.
this.usernameCallbackHandler.handle(new UsernameCallback(System.getProperty("user.name")));
}
@@ -117,7 +117,8 @@ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List NativeConstants.SEED_LENGTH) {
+ if (this.publicKeyRequested && fromServer.getPayloadLength() > NativeConstants.SEED_LENGTH + 1) { // auth data is null terminated
// Servers affected by Bug#70865 could send Auth Switch instead of key after Public Key Retrieval,
// so we check payload length to detect that.
@@ -167,7 +168,9 @@ protected byte[] encryptPassword() {
protected byte[] encryptPassword(String transformation) {
byte[] input = null;
- input = this.password != null ? StringUtils.getBytesNullTerminated(this.password, this.protocol.getPasswordCharacterEncoding()) : new byte[] { 0 };
+ input = this.password != null
+ ? StringUtils.getBytesNullTerminated(this.password, this.protocol.getServerSession().getCharsetSettings().getPasswordCharacterEncoding())
+ : new byte[] { 0 };
byte[] mysqlScrambleBuff = new byte[input.length];
Security.xorString(input, mysqlScrambleBuff, this.seed.getBytes(), input.length);
return ExportControlled.encryptWithRSAPublicKey(mysqlScrambleBuff, ExportControlled.decodeRSAPublicKey(this.publicKeyString), transformation);
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/OkPacket.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/OkPacket.java
index 87d292ccc..6924902b2 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/OkPacket.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/OkPacket.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -29,20 +29,24 @@
package com.mysql.cj.protocol.a.result;
+import static com.mysql.cj.protocol.a.NativeServerSession.SERVER_SESSION_STATE_CHANGED;
+
import com.mysql.cj.protocol.ProtocolEntity;
import com.mysql.cj.protocol.a.NativeConstants.IntegerDataType;
import com.mysql.cj.protocol.a.NativeConstants.StringSelfDataType;
import com.mysql.cj.protocol.a.NativePacketPayload;
+import com.mysql.cj.protocol.a.NativeServerSessionStateController.NativeServerSessionStateChanges;
public class OkPacket implements ProtocolEntity {
-
private long updateCount = -1;
private long updateID = -1;
private int statusFlags = 0;
private int warningCount = 0;
private String info = null;
+ private NativeServerSessionStateChanges sessionStateChanges;
- public OkPacket() {
+ private OkPacket() {
+ this.sessionStateChanges = new NativeServerSessionStateChanges();
}
public static OkPacket parse(NativePacketPayload buf, String errorMessageEncoding) {
@@ -56,6 +60,11 @@ public static OkPacket parse(NativePacketPayload buf, String errorMessageEncodin
ok.setStatusFlags((int) buf.readInteger(IntegerDataType.INT2));
ok.setWarningCount((int) buf.readInteger(IntegerDataType.INT2));
ok.setInfo(buf.readString(StringSelfDataType.STRING_TERM, errorMessageEncoding)); // info
+
+ // read session state changes info
+ if ((ok.getStatusFlags() & SERVER_SESSION_STATE_CHANGED) > 0) {
+ ok.sessionStateChanges.init(buf, errorMessageEncoding);
+ }
return ok;
}
@@ -98,4 +107,9 @@ public int getWarningCount() {
public void setWarningCount(int warningCount) {
this.warningCount = warningCount;
}
-}
+
+ public NativeServerSessionStateChanges getSessionStateChanges() {
+ return this.sessionStateChanges;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsCursor.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsCursor.java
index a244682d9..a0fd6035e 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsCursor.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsCursor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -76,7 +76,7 @@ public class ResultsetRowsCursor extends AbstractResultsetRows implements Result
*/
private boolean firstFetchCompleted = false;
- protected NativeMessageBuilder commandBuilder = new NativeMessageBuilder(); // TODO use shared builder
+ protected NativeMessageBuilder commandBuilder = null;
/**
* Creates a new cursor-backed row provider.
@@ -91,6 +91,7 @@ public ResultsetRowsCursor(NativeProtocol ioChannel, ColumnDefinition columnDefi
this.metadata = columnDefinition;
this.protocol = ioChannel;
this.rowFactory = new BinaryRowFactory(this.protocol, this.metadata, Concurrency.READ_ONLY, false);
+ this.commandBuilder = new NativeMessageBuilder(this.protocol.getServerSession().supportsQueryAttributes());
}
@Override
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsStreaming.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsStreaming.java
index db3cd3aaf..9cba95947 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsStreaming.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/a/result/ResultsetRowsStreaming.java
@@ -77,7 +77,7 @@ public class ResultsetRowsStreaming extends AbstractRe
private ProtocolEntityFactory resultSetFactory;
- private NativeMessageBuilder commandBuilder = new NativeMessageBuilder(); // TODO use shared builder
+ private NativeMessageBuilder commandBuilder = null;
/**
* Creates a new RowDataDynamic object.
@@ -100,6 +100,7 @@ public ResultsetRowsStreaming(NativeProtocol io, ColumnDefinition columnDefiniti
this.resultSetFactory = resultSetFactory;
this.rowFactory = this.isBinaryEncoded ? new BinaryRowFactory(this.protocol, this.metadata, Concurrency.READ_ONLY, true)
: new TextRowFactory(this.protocol, this.metadata, Concurrency.READ_ONLY, true);
+ this.commandBuilder = new NativeMessageBuilder(this.protocol.getServerSession().supportsQueryAttributes());
}
@Override
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/FieldFactory.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/FieldFactory.java
index 319591b5d..7e156489c 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/FieldFactory.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/FieldFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -100,7 +100,7 @@ private Field columnMetaDataToField(ColumnMetaData col, String characterSet) {
collationIndex = (int) col.getCollation();
}
- String encoding = CharsetMapping.getJavaEncodingForCollationIndex(collationIndex);
+ String encoding = CharsetMapping.getStaticJavaEncodingForCollationIndex(collationIndex);
MysqlType mysqlType = findMysqlType(col.getType(), col.getContentType(), col.getFlags(), collationIndex);
int mysqlTypeId = xProtocolTypeToMysqlType(col.getType(), col.getContentType());
@@ -174,7 +174,7 @@ private MysqlType findMysqlType(FieldType type, int contentType, int flags, int
case XPROTOCOL_COLUMN_BYTES_CONTENT_TYPE_JSON:
return MysqlType.JSON;
default:
- if (collationIndex == 33) {
+ if (collationIndex == 33) { // TODO what if other utf8 or utf8mb4 collation ?
return MysqlType.VARBINARY;
}
return MysqlType.VARCHAR;
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/Notice.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/Notice.java
index ab10533f3..322e917fc 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/Notice.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/Notice.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -50,23 +50,21 @@ public class Notice implements ProtocolEntity {
public static Notice getInstance(XMessage message) {
Frame notice = (Frame) message.getMessage();
- if (notice.getScope() != Frame.Scope.GLOBAL) { // TODO should we handle global notices somehow? What frame types are applicable there?
- switch (notice.getType()) {
- case Frame.Type.WARNING_VALUE:
- return new XWarning(notice);
-
- case Frame.Type.SESSION_VARIABLE_CHANGED_VALUE:
- return new XSessionVariableChanged(notice);
-
- case Frame.Type.SESSION_STATE_CHANGED_VALUE:
- return new XSessionStateChanged(notice);
-
- case Frame.Type.GROUP_REPLICATION_STATE_CHANGED_VALUE:
- // TODO
- break;
- default:
- break;
- }
+ switch (notice.getType()) {
+ case Frame.Type.WARNING_VALUE:
+ return new XWarning(notice);
+
+ case Frame.Type.SESSION_VARIABLE_CHANGED_VALUE:
+ return new XSessionVariableChanged(notice);
+
+ case Frame.Type.SESSION_STATE_CHANGED_VALUE:
+ return new XSessionStateChanged(notice);
+
+ case Frame.Type.GROUP_REPLICATION_STATE_CHANGED_VALUE:
+ // TODO
+ break;
+ default:
+ break;
}
return new Notice(notice);
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XAuthenticationProvider.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XAuthenticationProvider.java
index 56a965c44..0af197f65 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XAuthenticationProvider.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XAuthenticationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -43,7 +43,6 @@
import com.mysql.cj.exceptions.WrongArgumentException;
import com.mysql.cj.protocol.AuthenticationProvider;
import com.mysql.cj.protocol.Protocol;
-import com.mysql.cj.protocol.ServerSession;
import com.mysql.cj.util.StringUtils;
import com.mysql.cj.xdevapi.XDevAPIError;
@@ -59,12 +58,12 @@ public void init(Protocol prot, PropertySet propertySet, ExceptionInte
}
@Override
- public void connect(ServerSession serverSession, String userName, String password, String database) {
- changeUser(serverSession, userName, password, database);
+ public void connect(String userName, String password, String database) {
+ changeUser(userName, password, database);
}
@Override
- public void changeUser(ServerSession serverSession, String userName, String password, String database) {
+ public void changeUser(String userName, String password, String database) {
boolean overTLS = ((XServerCapabilities) this.protocol.getServerSession().getCapabilities()).getTls();
RuntimeProperty authMechProp = this.protocol.getPropertySet().getEnumProperty(PropertyKey.xdevapiAuth);
List tryAuthMech;
@@ -139,8 +138,4 @@ public void changeUser(ServerSession serverSession, String userName, String pass
this.protocol.afterHandshake();
}
- @Override
- public String getEncodingForHandshake() {
- return null; // TODO
- }
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XProtocol.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XProtocol.java
index 330bb807d..722ddc22e 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XProtocol.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -49,7 +49,6 @@
import java.util.function.Consumer;
import com.google.protobuf.GeneratedMessageV3;
-import com.mysql.cj.CharsetMapping;
import com.mysql.cj.Constants;
import com.mysql.cj.Messages;
import com.mysql.cj.QueryResult;
@@ -74,6 +73,8 @@
import com.mysql.cj.exceptions.MysqlErrorNumbers;
import com.mysql.cj.exceptions.SSLParamsException;
import com.mysql.cj.exceptions.WrongArgumentException;
+import com.mysql.cj.log.Log;
+import com.mysql.cj.log.LogFactory;
import com.mysql.cj.protocol.AbstractProtocol;
import com.mysql.cj.protocol.ColumnDefinition;
import com.mysql.cj.protocol.ExportControlled;
@@ -144,22 +145,6 @@ public class XProtocol extends AbstractProtocol implements Protocol, ProtocolEntityFactory extends ProtocolEntity, XMessage>> messageToProtocolEntityFactory = new HashMap<>();
- public XProtocol(String host, int port, String defaultSchema, PropertySet propertySet) {
-
- this.defaultSchemaName = defaultSchema;
-
- // Override common connectTimeout with xdevapi.connect-timeout to provide unified logic in StandardSocketFactory
- RuntimeProperty connectTimeout = propertySet.getIntegerProperty(PropertyKey.connectTimeout);
- RuntimeProperty xdevapiConnectTimeout = propertySet.getIntegerProperty(PropertyKey.xdevapiConnectTimeout);
- if (xdevapiConnectTimeout.isExplicitlySet() || !connectTimeout.isExplicitlySet()) {
- connectTimeout.setValue(xdevapiConnectTimeout.getValue());
- }
-
- SocketConnection socketConn = new NativeSocketConnection();
- socketConn.connect(host, port, propertySet, null, null, 0);
- init(null, socketConn, propertySet, null);
- }
-
public XProtocol(HostInfo hostInfo, PropertySet propertySet) {
String host = hostInfo.getHost();
if (host == null || StringUtils.isEmptyOrWhitespaceOnly(host)) {
@@ -187,6 +172,9 @@ public XProtocol(HostInfo hostInfo, PropertySet propertySet) {
public void init(Session sess, SocketConnection socketConn, PropertySet propSet, TransactionEventHandler trManager) {
super.init(sess, socketConn, propSet, trManager);
+ // Session is not kept, so we need to do this
+ this.log = LogFactory.getLogger(getPropertySet().getStringProperty(PropertyKey.logger).getStringValue(), Log.LOGGER_INSTANCE_NAME);
+
this.messageBuilder = new XMessageBuilder();
this.authProvider = new XAuthenticationProvider();
@@ -237,7 +225,7 @@ public void negotiateSSLConnection() {
sendCapabilities(tlsCapabilities);
try {
- this.socketConnection.performTlsHandshake(null); //(this.serverSession);
+ this.socketConnection.performTlsHandshake(null, this.log);
} catch (SSLParamsException | FeatureNotAvailableException | IOException e) {
throw new CJCommunicationsException(e);
}
@@ -378,28 +366,21 @@ public void beforeHandshake() {
}
RuntimeProperty xdevapiTlsVersions = this.propertySet.getStringProperty(PropertyKey.xdevapiTlsVersions);
- RuntimeProperty jdbcEnabledTlsProtocols = this.propertySet.getStringProperty(PropertyKey.enabledTLSProtocols);
+ RuntimeProperty jdbcEnabledTlsProtocols = this.propertySet.getStringProperty(PropertyKey.tlsVersions);
if (xdevapiTlsVersions.isExplicitlySet()) {
if (sslMode.getValue() == SslMode.DISABLED) {
throw ExceptionFactory.createException(WrongArgumentException.class,
"Option '" + PropertyKey.xdevapiTlsVersions.getKeyName() + "' can not be specified when SSL connections are disabled.");
}
- if (xdevapiTlsVersions.getValue().trim().isEmpty()) {
- throw ExceptionFactory.createException(WrongArgumentException.class,
- "At least one TLS protocol version must be specified in '" + PropertyKey.xdevapiTlsVersions.getKeyName() + "' list.");
- }
String[] tlsVersions = xdevapiTlsVersions.getValue().split("\\s*,\\s*");
List tryProtocols = Arrays.asList(tlsVersions);
ExportControlled.checkValidProtocols(tryProtocols);
jdbcEnabledTlsProtocols.setValue(xdevapiTlsVersions.getValue());
-
- } else if (!jdbcEnabledTlsProtocols.isExplicitlySet()) {
- jdbcEnabledTlsProtocols.setValue(xdevapiTlsVersions.getValue());
}
RuntimeProperty xdevapiTlsCiphersuites = this.propertySet.getStringProperty(PropertyKey.xdevapiTlsCiphersuites);
- RuntimeProperty jdbcEnabledSslCipherSuites = this.propertySet.getStringProperty(PropertyKey.enabledSSLCipherSuites);
+ RuntimeProperty jdbcEnabledSslCipherSuites = this.propertySet.getStringProperty(PropertyKey.tlsCiphersuites);
if (xdevapiTlsCiphersuites.isExplicitlySet()) {
if (sslMode.getValue() == SslMode.DISABLED) {
throw ExceptionFactory.createException(WrongArgumentException.class,
@@ -407,9 +388,6 @@ public void beforeHandshake() {
}
jdbcEnabledSslCipherSuites.setValue(xdevapiTlsCiphersuites.getValue());
-
- } else if (!jdbcEnabledSslCipherSuites.isExplicitlySet()) {
- jdbcEnabledSslCipherSuites.setValue(xdevapiTlsCiphersuites.getValue());
}
boolean verifyServerCert = sslMode.getValue() == SslMode.VERIFY_CA || sslMode.getValue() == SslMode.VERIFY_IDENTITY;
@@ -437,7 +415,7 @@ public void beforeHandshake() {
}
}
- if (xdevapiSslMode.getValue() != XdevapiSslMode.DISABLED) {
+ if (jdbcSslMode.getValue() != SslMode.DISABLED) {
negotiateSSLConnection();
}
@@ -519,7 +497,7 @@ public void connect(String user, String password, String database) {
this.currDatabase = database;
beforeHandshake();
- this.authProvider.connect(null, user, password, database);
+ this.authProvider.connect(user, password, database);
}
public void changeUser(String user, String password, String database) {
@@ -527,7 +505,7 @@ public void changeUser(String user, String password, String database) {
this.currPassword = password;
this.currDatabase = database;
- this.authProvider.changeUser(null, user, password, database);
+ this.authProvider.changeUser(user, password, database);
}
public void afterHandshake() {
@@ -577,7 +555,7 @@ public void readAuthenticateOk() {
if (notice instanceof XSessionStateChanged) {
switch (((XSessionStateChanged) notice).getParamType()) {
case Notice.SessionStateChanged_CLIENT_ID_ASSIGNED:
- this.getServerSession().setThreadId(((XSessionStateChanged) notice).getValue().getVUnsignedInt());
+ this.getServerSession().getCapabilities().setThreadId(((XSessionStateChanged) notice).getValue().getVUnsignedInt());
break;
case Notice.SessionStateChanged_ACCOUNT_EXPIRED:
// TODO
@@ -683,21 +661,20 @@ public void drainRows() {
}
}
- // TODO: put this in CharsetMapping..
- public static Map COLLATION_NAME_TO_COLLATION_INDEX = new java.util.HashMap<>();
-
- static {
- for (int i = 0; i < CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length; ++i) {
- COLLATION_NAME_TO_COLLATION_INDEX.put(CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[i], i);
- }
+ public ColumnDefinition readMetadata() {
+ return readMetadata(null);
}
- public ColumnDefinition readMetadata() {
+ public ColumnDefinition readMetadata(Consumer noticeConsumer) {
try {
+ List notices;
List fromServer = new LinkedList<>();
do { // use this construct to read at least one
- fromServer.add((ColumnMetaData) this.reader.readMessage(null, ServerMessages.Type.RESULTSET_COLUMN_META_DATA_VALUE).getMessage());
- // TODO put notices somewhere like it's done eg. in readStatementExecuteOk(): builder.addNotice(this.reader.read(Frame.class));
+ XMessage mess = this.reader.readMessage(null, ServerMessages.Type.RESULTSET_COLUMN_META_DATA_VALUE);
+ if (noticeConsumer != null && (notices = mess.getNotices()) != null) {
+ notices.stream().forEach(noticeConsumer::accept);
+ }
+ fromServer.add((ColumnMetaData) mess.getMessage());
} while (((SyncMessageReader) this.reader).getNextNonNoticeMessageType() == ServerMessages.Type.RESULTSET_COLUMN_META_DATA_VALUE);
ArrayList metadata = new ArrayList<>(fromServer.size());
@SuppressWarnings("unchecked")
@@ -999,7 +976,7 @@ public void reset() {
}
}
- this.authProvider.changeUser(null, this.currUser, this.currPassword, this.currDatabase);
+ this.authProvider.changeUser(this.currUser, this.currPassword, this.currDatabase);
}
// No prepared statements survived to Mysqlx.Session.Reset. Reset all related control structures.
@@ -1021,10 +998,6 @@ public void changeDatabase(String database) {
// TODO: Figure out how this is relevant for X Protocol client Session
}
- public String getPasswordCharacterEncoding() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
public boolean versionMeetsMinimum(int major, int minor, int subminor) {
//TODO: expose this via ServerVersion so calls look like x.getServerVersion().meetsMinimum(major, minor, subminor)
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerCapabilities.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerCapabilities.java
index ede5e68dd..c8730c72e 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerCapabilities.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerCapabilities.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -55,6 +55,9 @@ public class XServerCapabilities implements ServerCapabilities {
static String SUBKEY_COMPRESSION_SERVER_COMBINE_MIXED_MESSAGES = "server_combine_mixed_messages";
static String SUBKEY_COMPRESSION_SERVER_MAX_COMBINE_MESSAGES = "server_max_combine_messages";
+ /** Server-assigned client-id. */
+ private long clientId = -1;
+
public XServerCapabilities(Map capabilities) {
this.capabilities = capabilities;
}
@@ -118,13 +121,23 @@ public ServerVersion getServerVersion() {
}
@Override
- public void setServerVersion(ServerVersion serverVersion) {
+ public boolean serverSupportsFracSecs() {
+ return true;
+ }
+
+ @Override
+ public int getServerDefaultCollationIndex() {
// TODO Auto-generated method stub
+ return 0;
+ }
+ @Override
+ public long getThreadId() {
+ return this.clientId;
}
@Override
- public boolean serverSupportsFracSecs() {
- return true;
+ public void setThreadId(long threadId) {
+ this.clientId = threadId;
}
}
diff --git a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerSession.java b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerSession.java
index 019c2ee59..61461b63a 100644
--- a/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerSession.java
+++ b/src/main/protocol-impl/java/com/mysql/cj/protocol/x/XServerSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -32,6 +32,7 @@
import java.util.Map;
import java.util.TimeZone;
+import com.mysql.cj.CharsetSettings;
import com.mysql.cj.ServerVersion;
import com.mysql.cj.exceptions.CJOperationNotSupportedException;
import com.mysql.cj.exceptions.ExceptionFactory;
@@ -41,8 +42,6 @@
public class XServerSession implements ServerSession {
XServerCapabilities serverCapabilities = null;
- /** Server-assigned client-id. */
- private long clientId = -1;
private TimeZone defaultTimeZone = TimeZone.getDefault();
@@ -54,7 +53,6 @@ public ServerCapabilities getCapabilities() {
@Override
public void setCapabilities(ServerCapabilities capabilities) {
this.serverCapabilities = (XServerCapabilities) capabilities;
-
}
@Override
@@ -82,16 +80,6 @@ public void setOldStatusFlags(int statusFlags) {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}
- @Override
- public int getServerDefaultCollationIndex() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public void setServerDefaultCollationIndex(int serverDefaultCollationIndex) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
@Override
public int getTransactionState() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
@@ -147,6 +135,11 @@ public void setClientParam(long clientParam) {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}
+ @Override
+ public boolean hasLongColumnInfo() {
+ throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
+ }
+
@Override
public boolean useMultiResults() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
@@ -158,7 +151,7 @@ public boolean isEOFDeprecated() {
}
@Override
- public boolean hasLongColumnInfo() {
+ public boolean supportsQueryAttributes() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}
@@ -182,11 +175,6 @@ public void setServerVariables(Map serverVariables) {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}
- @Override
- public boolean characterSetNamesMatches(String mysqlEncodingName) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
@Override
public ServerVersion getServerVersion() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
@@ -197,71 +185,6 @@ public boolean isVersion(ServerVersion version) {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}
- @Override
- public String getServerDefaultCharset() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public String getErrorMessageEncoding() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public void setErrorMessageEncoding(String errorMessageEncoding) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public int getMaxBytesPerChar(String javaCharsetName) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public int getMaxBytesPerChar(Integer charsetIndex, String javaCharsetName) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public String getEncodingForIndex(int collationIndex) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public void configureCharacterSets() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public String getCharacterSetMetadata() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public void setCharacterSetMetadata(String characterSetMetadata) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public int getMetadataCollationIndex() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public void setMetadataCollationIndex(int metadataCollationIndex) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public String getCharacterSetResultsOnServer() {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
- @Override
- public void setCharacterSetResultsOnServer(String characterSetResultsOnServer) {
- throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
- }
-
@Override
public boolean isLowerCaseTableNames() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
@@ -292,16 +215,6 @@ public boolean isServerTruncatesFracSecs() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}
- @Override
- public long getThreadId() {
- return this.clientId;
- }
-
- @Override
- public void setThreadId(long threadId) {
- this.clientId = threadId;
- }
-
@Override
public boolean isAutoCommit() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
@@ -323,4 +236,16 @@ public void setSessionTimeZone(TimeZone sessionTimeZone) {
public TimeZone getDefaultTimeZone() {
return this.defaultTimeZone;
}
+
+ @Override
+ public CharsetSettings getCharsetSettings() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setCharsetSettings(CharsetSettings charsetSettings) {
+ // TODO Auto-generated method stub
+
+ }
}
diff --git a/src/main/resources/com/mysql/cj/LocalizedErrorMessages.properties b/src/main/resources/com/mysql/cj/LocalizedErrorMessages.properties
index b0cf3c9ed..2b9704d90 100644
--- a/src/main/resources/com/mysql/cj/LocalizedErrorMessages.properties
+++ b/src/main/resources/com/mysql/cj/LocalizedErrorMessages.properties
@@ -35,11 +35,21 @@ Milliseconds=ms
#
# Classes
#
+AuthenticationKerberosClientPlugin.FailAuthenticateUser=No cached TGT found in the system or failed authenticating the user in the Kerberos server.
+AuthenticationKerberosClientPlugin.FailCreateSaslClient=Failed creating a SASL client for the authentication mechanism ''{0}''.
+AuthenticationKerberosClientPlugin.ErrProcessingAuthIter=Error while processing an authentication iteration for the authentication mechanism ''{0}''.
+
AuthenticationLdapSaslClientPlugin.UnsupportedAuthMech=Unsupported SASL authentication mechanism ''{0}''.
AuthenticationLdapSaslClientPlugin.MissingLdapServerHostname=An LDAP Server hostname could not be acquired. One must be provided by either using the connection option ''ldapServerHostname'' or by setting the system property ''java.security.krb5.kdc''.
AuthenticationLdapSaslClientPlugin.FailCreateSaslClient=Failed creating a SASL client for the authentication mechanism ''{0}''.
AuthenticationLdapSaslClientPlugin.ErrProcessingAuthIter=Error while processing an authentication iteration for the authentication mechanism ''{0}''.
+AuthenticationOciClientPlugin.SdkNotFound=The OCI SDK could not be found or is not installed.
+AuthenticationOciClientPlugin.OciConfigFileError=OCI configuration file could not be read.
+AuthenticationOciClientPlugin.OciConfigFileMissingEntry=OCI configuration file does not contain a ''fingerprint'' or ''key_file'' entry.
+AuthenticationOciClientPlugin.PrivateKeyNotFound=Private key could not be found at location given by OCI configuration entry ''key_file''.
+AuthenticationOciClientPlugin.PrivateKeyNotValid=OCI configuration entry ''key_file'' does not reference a valid key file.
+
AuthenticationProvider.BadAuthenticationPlugin=Unable to load authentication plugin ''{0}''.
AuthenticationProvider.BadDefaultAuthenticationPlugin=Improper value "{0}" for property ''defaultAuthenticationPlugin''.
AuthenticationProvider.DefaultAuthenticationPluginIsNotListed=Default authentication plugin "{0}" is neither one of the built-in plugins nor one of the plugins listed in ''authenticationPlugins''.
@@ -93,6 +103,8 @@ Clob.11=Cannot truncate CLOB of length
Clob.12=\ to length of
Clob.13=.
+Collection.DocIdMismatch=Replacement document has an _id that is different than the matched document.
+
ColumnDefinition.0={0} is not applicable to the {1} type of column ''{2}''.
ColumnDefinition.1=Length must be specified before decimals for column ''{0}''.
@@ -101,13 +113,12 @@ Connection.1=Cannot connect to MySQL server on {0}:{1}.\n\nMake sure that there
Connection.2=No operations allowed after connection closed.
Connection.3=Can''t call commit when autocommit=true
Connection.4=Communications link failure during commit(). Transaction resolution unknown.
-Connection.5=Java does not support the MySQL character encoding ''{0}''.
-Connection.6=Unknown initial character set index ''{0}'' received from server. Initial client character set can be forced via the ''characterEncoding'' property.
+Connection.5=Unknown Java encoding for the character set with index ''{0}''. Use the ''customCharsetMapping'' property to force it.
+Connection.6=Unknown character set index ''{0}'' received from server. The appropriate client character set can be forced via the ''characterEncoding'' property.
Connection.7=Can''t map {0} given for characterSetResults to a supported MySQL encoding.
Connection.8=Unable to use encoding: {0}
Connection.9=No timezone mapping entry for ''{0}''
Connection.10=Illegal connection port value ''{0}''
-Connection.11=Unknown character set index ''{0}'' was received from server.
Connection.12=Could not map transaction isolation ''{0}'' to a valid JDBC level.
Connection.13=Could not retrieve transaction isolation level from server
Connection.15=Connection setting too low for ''maxAllowedPacket''. When ''useServerPrepStmts=true'', ''maxAllowedPacket'' must be higher than {0}. Check also ''max_allowed_packet'' in MySQL configuration files.
@@ -291,15 +302,13 @@ MysqlIO.105=Negative skip length not allowed
MysqlIO.106=Value ''0000-00-00'' can not be represented as java.sql.Date
MysqlIO.107=Value ''0000-00-00'' can not be represented as java.sql.Timestamp
MysqlIO.111=Could not allocate packet of {0} bytes required for "LOAD DATA LOCAL INFILE" operation. Try increasing max heap allocation for JVM or decreasing server variable ''max_allowed_packet''
-MysqlIO.113=Invalid character set index for encoding: {0}
+MysqlIO.113=Invalid character set index {0} for handshake, only values 1-255 are allowed.
MysqlIO.EOF=Can not read response from server. Expected to read {0} bytes, read {1} bytes before connection was unexpectedly lost.
MysqlIO.NoInnoDBStatusFound=No InnoDB status output returned by server.
MysqlIO.InnoDBStatusFailed=Couldn''t retrieve InnoDB status due to underlying exception:
MysqlIO.LoadDataLocalNotAllowed=Server asked for stream in response to "LOAD DATA LOCAL INFILE" but functionality is not enabled at client by setting "allowLoadLocalInfile=true" or specifying a path with ''allowLoadLocalInfileInPath''.
MysqlIo.BadQueryInterceptor=Unable to load query interceptor ''{0}''.
-MysqlNativePasswordPlugin.1=Unsupported character encoding ''{0}'' for ''passwordCharacterEncoding'' or ''characterEncoding''.
-
MysqlParameterMetadata.0=Parameter metadata not available for the given statement
MysqlParameterMetadata.1=Parameter index of ''{0}'' is invalid.
MysqlParameterMetadata.2=Parameter index of ''{0}'' is greater than number of parameters, which is ''{1}''.
@@ -363,7 +372,7 @@ PreparedStatement.25=Connection is read-only.
PreparedStatement.26=Queries leading to data modification are not allowed
PreparedStatement.34=Connection is read-only.
PreparedStatement.35=Queries leading to data modification are not allowed
-PreparedStatement.37=Can not issue executeUpdate() or executeLargeUpdate() for SELECTs
+PreparedStatement.37=Can not issue executeUpdate() or executeLargeUpdate() with statements that produce result sets
PreparedStatement.40=No value specified for parameter
PreparedStatement.43=PreparedStatement created, but used 1 or fewer times. It is more efficient to prepare statements once, and re-use them many times
PreparedStatement.48=PreparedStatement has been closed. No further operations allowed.
@@ -442,7 +451,7 @@ ResultSet.Operation_not_allowed_after_ResultSet_closed_144=Operation not allowed
ResultSet.Before_start_of_result_set_146=Before start of result set
ResultSet.After_end_of_result_set_148=After end of result set
ResultSet.Query_generated_no_fields_for_ResultSet_133=Query generated no fields for ResultSet
-ResultSet.ResultSet_is_from_UPDATE._No_Data_115=ResultSet is from UPDATE. No Data.
+ResultSet.ResultSet_is_from_UPDATE._No_Data_115=Not a navigable ResultSet.
ResultSet.Invalid_value_for_getFloat()_-____68=Invalid value for getFloat() - ''
ResultSet.Invalid_value_for_getInt()_-____74=Invalid value for getInt() - ''
@@ -484,6 +493,15 @@ ResultSet.UnknownSourceType=Cannot decode value of unknown source type
ResultSet.InvalidTimeValue=The value ''{0}'' is an invalid TIME value. JDBC Time objects represent a wall-clock time and not a duration as MySQL treats them. If you are treating this type as a duration, consider retrieving this value as a string and dealing with it according to your requirements.
ResultSet.InvalidZeroDate=Zero date value prohibited
+ValueEncoder.WrongTinyIntValueType=Type ''{0}'' cannot be encoded into a MySQL TINYINT value.
+ValueEncoder.WrongSmallIntValueType=Type ''{0}'' cannot be encoded into a MySQL SMALLINT value.
+ValueEncoder.WrongIntValueType=Type ''{0}'' cannot be encoded into a MySQL INT value.
+ValueEncoder.WrongBigIntValueType=Type ''{0}'' cannot be encoded into a MySQL BIGINT value.
+ValueEncoder.WrongTimeValueType=Type ''{0}'' cannot be encoded into a MySQL TIME value.
+ValueEncoder.WrongDateValueType=Type ''{0}'' cannot be encoded into a MySQL DATE value.
+ValueEncoder.WrongDateTimeValueType=Type ''{0}'' cannot be encoded into a MySQL DATETIME value.
+ValueEncoder.WrongTimestampValueType=Type ''{0}'' cannot be encoded into a MySQL TIMESTAMP value.
+
#
# Usage advisor messages for ResultSets
#
@@ -579,7 +597,6 @@ Session.Create.Failover.0=Unable to connect to any of the target hosts.
Sha256PasswordPlugin.0=Unable to read public key {0}
Sha256PasswordPlugin.1=Unable to close public key file
Sha256PasswordPlugin.2=Public Key Retrieval is not allowed
-Sha256PasswordPlugin.3=Unsupported character encoding ''{0}'' for ''passwordCharacterEncoding'' or ''characterEncoding''.
Schema.CreateCollection=The server doesn't support the requested operation. Please update the MySQL Server and or Client library
@@ -608,9 +625,9 @@ Statement.35=Queries leading to data modification are not allowed.
Statement.40=Can not issue INSERT/UPDATE/DELETE with executeQuery().
Statement.42=Connection is read-only.
Statement.43=Queries leading to data modification are not allowed.
-Statement.46=Can not issue SELECT via executeUpdate() or executeLargeUpdate().
+Statement.46=Statement.executeUpdate() or Statement.executeLargeUpdate() cannot issue statements that produce result sets.
Statement.AlreadyClosed=No operations allowed after statement closed.
-Statement.57=Can not issue data manipulation statements with executeQuery().
+Statement.57=Statement.executeQuery() cannot issue statements that do not produce result sets.
Statement.59=Can not issue NULL query.
Statement.61=Can not issue empty query.
Statement.63=Statement not closed explicitly. You should call close() on created Statement instances from your code to be more efficient.
@@ -619,10 +636,16 @@ Statement.GeneratedKeysNotRequested=Generated keys not requested. You need to sp
Statement.ConnectionKilledDueToTimeout=Connection closed to due to statement timeout being reached and "queryTimeoutKillsConnection" being set to "true".
Statement.UnsupportedSQLType=Unsupported SQL type:
+StringInspector.1=The source string must not be null.
+StringInspector.2=Illegal argument value {0} for openingMarkers and/or {1} for closingMarkers. These cannot be null and must have the same length.
+StringInspector.3=Illegal argument value {0} for overridingMarkers. These cannot be null and must be a sub-set of openingMarkers {1}.
+StringInspector.4=The start position must be zero or a positive number.
+StringInspector.5=The start position must must not be higher than the stop position.
+StringInspector.6=The stop position must be zero or a positive number.
+StringInspector.7=The stop position must must not be higher than the length of the source string.
+StringInspector.8=The delimiter string must not be null.
StringUtils.0=Unsupported character encoding ''{0}''
-StringUtils.15=Illegal argument value {0} for openingMarkers and/or {1} for closingMarkers. These cannot be null and must have the same length.
-StringUtils.16=Illegal argument value {0} for overridingMarkers. These cannot be null and must be a sub-set of openingMarkers {1}.
StringUtils.badIntFormat=Invalid integer format for value ''{0}''
TimeUtil.0=Illegal hour value ''{0}'' for java.sql.Time type in value ''{1}''.
@@ -742,6 +765,12 @@ SQLError.67=Invalid argument value
SQLError.68=Driver not capable
SQLError.69=Timeout expired
+#
+# Log messages
+#
+
+QueryAttributes.SetButNotSupported=Query attributes have been set but the server does not support them.
+
#
# ConnectionProperty Categories
#
@@ -770,15 +799,15 @@ ConnectionProperties.categoryUserDefined=User-defined properties
# ConnectionProperty Descriptions
#
-ConnectionProperties.loadDataLocal=Should the driver allow use of "LOAD DATA LOCAL INFILE ..."?[CR]Setting to "true" overrides whatever path is set in ''allowLoadLocalInfileInPath'', allowing uploading files from any location.
-ConnectionProperties.loadDataLocalInPath=Enables "LOAD DATA LOCAL INFILE ..." statements, but only allows loading files from the specified path. Files within sub-directories are also allowed, but relative paths or symlinks that fall outside this path are forbidden.
-ConnectionProperties.allowSourceDownConnections=By default, a replication-aware connection will fail to connect when configured source hosts are all unavailable at initial connection. Setting this property to ''true'' allows to establish the initial connection, by failing over to the replica servers, in read-only state. It won''t prevent subsequent failures when switching back to the source hosts i.e. by setting the replication connection to read/write state.
-ConnectionProperties.allowReplicaDownConnections=By default, a replication-aware connection will fail to connect when configured replica hosts are all unavailable at initial connection. Setting this property to ''true'' allows to establish the initial connection. It won''t prevent failures when switching to replicas i.e. by setting the replication connection to read-only state. The property ''readFromSourceWhenNoReplicas'' should be used for this purpose.
-ConnectionProperties.readFromSourceWhenNoReplicas=Replication-aware connections distribute load by using the source hosts when in read/write state and by using the replica hosts when in read-only state. If, when setting the connection to read-only state, none of the replica hosts are available, an SQLException is thrown back. Setting this property to ''true'' allows to fail over to the source hosts, while setting the connection state to read-only, when no replica hosts are available at switch instant.
ConnectionProperties.allowMultiQueries=Allow the use of '';'' to delimit multiple queries during one statement (true/false). Default is ''false'', and it does not affect the addBatch() and executeBatch() methods, which rely on rewriteBatchStatements instead.
ConnectionProperties.allowNANandINF=Should the driver allow NaN or +/- INF values in PreparedStatement.setDouble()?
+ConnectionProperties.allowPublicKeyRetrieval=Allows special handshake round-trip to get an RSA public key directly from server.
+ConnectionProperties.allowReplicaDownConnections=By default, a replication-aware connection will fail to connect when configured replica hosts are all unavailable at initial connection. Setting this property to ''true'' allows to establish the initial connection. It won''t prevent failures when switching to replicas i.e. by setting the replication connection to read-only state. The property ''readFromSourceWhenNoReplicas'' should be used for this purpose.
+ConnectionProperties.allowSourceDownConnections=By default, a replication-aware connection will fail to connect when configured source hosts are all unavailable at initial connection. Setting this property to ''true'' allows to establish the initial connection, by failing over to the replica servers, in read-only state. It won''t prevent subsequent failures when switching back to the source hosts i.e. by setting the replication connection to read/write state.
ConnectionProperties.allowUrlInLoadLocal=Should the driver allow URLs in "LOAD DATA LOCAL INFILE ..." statements?
+ConnectionProperties.allVersions=all versions
ConnectionProperties.alwaysSendSetIsolation=Should the driver always communicate with the database when Connection.setTransactionIsolation() is called? If set to false, the driver will only communicate with the database when the requested transaction isolation is different than the whichever is newer, the last value that was set via Connection.setTransactionIsolation(), or the value that was read from the server when the connection was established. Note that useLocalSessionState=true will force the same behavior as alwaysSendSetIsolation=false, regardless of how alwaysSendSetIsolation is set.
+ConnectionProperties.authenticationPlugins=Comma-delimited list of classes that implement the interface com.mysql.cj.protocol.AuthenticationPlugin. These plugins will be loaded at connection initialization and can be used together with their sever-side counterparts for authenticating users, unless they are also disabled in the connection property ''disabledAuthenticationPlugins''.
ConnectionProperties.autoClosePstmtStreams=Should the driver automatically call .close() on streams/readers passed as arguments via set*() methods?
ConnectionProperties.autoDeserialize=Should the driver automatically detect and de-serialize objects stored in BLOB fields?
ConnectionProperties.autoGenerateTestcaseScript=Should the driver dump the SQL it is executing, including server-side prepared statements to STDERR?
@@ -786,38 +815,59 @@ ConnectionProperties.autoReconnect=Should the driver try to re-establish stale a
ConnectionProperties.autoReconnectForPools=Use a reconnection strategy appropriate for connection pools (defaults to ''false'')
ConnectionProperties.autoSlowLog=Instead of using slowQueryThreshold* to determine if a query is slow enough to be logged, maintain statistics that allow the driver to determine queries that are outside the 99th percentile?
ConnectionProperties.blobsAreStrings=Should the driver always treat BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?
-ConnectionProperties.functionsNeverReturnBlobs=Should the driver always treat data from functions returning BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?
ConnectionProperties.blobSendChunkSize=Chunk size to use when sending BLOB/CLOBs via ServerPreparedStatements. Note that this value cannot exceed the value of "maxAllowedPacket" and, if that is the case, then this value will be corrected automatically.
ConnectionProperties.cacheCallableStatements=Should the driver cache the parsing stage of CallableStatements
+ConnectionProperties.cacheDefaultTimeZone=Caches client's default time zone. This results in better performance when dealing with time zone conversions in Date and Time data types, however it won't be aware of time zone changes if they happen at runtime.
ConnectionProperties.cachePrepStmts=Should the driver cache the parsing stage of PreparedStatements of client-side prepared statements, the "check" for suitability of server-side prepared and server-side prepared statements themselves?
ConnectionProperties.cacheRSMetadata=Should the driver cache ResultSetMetaData for Statements and PreparedStatements? (Req. JDK-1.4+, true/false, default ''false'')
ConnectionProperties.cacheServerConfiguration=Should the driver cache the results of ''SHOW VARIABLES'' and ''SHOW COLLATION'' on a per-URL basis?
ConnectionProperties.callableStmtCacheSize=If ''cacheCallableStmts'' is enabled, how many callable statements should be cached?
-ConnectionProperties.characterEncoding=What character encoding should the driver use when dealing with strings? (defaults is to ''autodetect'')
-ConnectionProperties.characterSetResults=Character set to tell the server to return results as.
+ConnectionProperties.characterEncoding=Instructs the server to set session system variables ''character_set_client'' and ''character_set_connection'' to the default character set for the specified Java encoding and set ''collation_connection'' to the default collation for this character set. If neither this property nor the property ''connectionCollation'' is set:[CR]For Connector/J 8.0.25 and earlier, the driver will try to use the server default character set;[CR]For Connector/J 8.0.26 and later, the driver will use "utf8mb4".
+ConnectionProperties.characterSetResults=Instructs the server to return the data encoded with the default character set for the specified Java encoding. If not set or set to "null", the server will send data in its original character set and the driver will decode it according to the result metadata.
+ConnectionProperties.clientCertificateKeyStorePassword=Password for the client certificates key store.
+ConnectionProperties.clientCertificateKeyStoreType=Key store type for client certificates.[CR]NULL or empty means use the default, which is "JKS". Standard key store types supported by the JVM are "JKS" and "PKCS12", your environment may have more available depending on what security products are installed and available to the JVM.
+ConnectionProperties.clientCertificateKeyStoreUrl=URL for the client certificate KeyStore[CR]If not specified, the property ''fallbackToSystemKeyStore'' determines if system-wide key store is used.
ConnectionProperties.clientInfoProvider=The name of a class that implements the com.mysql.cj.jdbc.ClientInfoProvider interface in order to support JDBC-4.0''s Connection.get/setClientInfo() methods
ConnectionProperties.clobberStreamingResults=This will cause a ''streaming'' ResultSet to be automatically closed, and any outstanding data still streaming from the server to be discarded if another query is executed before all the data has been read from the server.
ConnectionProperties.clobCharacterEncoding=The character encoding to use for sending and retrieving TEXT, MEDIUMTEXT and LONGTEXT values instead of the configured connection characterEncoding
ConnectionProperties.compensateOnDuplicateKeyUpdateCounts=Should the driver compensate for the update counts of "ON DUPLICATE KEY" INSERT statements (2 = 1, 0 = 1) when using prepared statements?
-ConnectionProperties.connectionCollation=If set, tells the server to use this collation in SET NAMES charset COLLATE connectionCollation. Also overrides the characterEncoding with those corresponding to the character set of this collation.
+ConnectionProperties.connectionAttributes=A comma-delimited list of user-defined key:value pairs (in addition to standard MySQL-defined key:value pairs) to be passed to MySQL Server for display as connection attributes in the PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS table. Example usage: connectionAttributes=key1:value1,key2:value2 This functionality is available for use with MySQL Server version 5.6 or later only. Earlier versions of MySQL Server do not support connection attributes, causing this configuration option to be ignored. Setting connectionAttributes=none will cause connection attribute processing to be bypassed, for situations where Connection creation/initialization speed is critical.
+ConnectionProperties.connectionCollation=Instructs the server to set session system variable ''collation_connection'' to the specified collation name and set ''character_set_client'' and ''character_set_connection'' to the corresponding character set. This property overrides the value of ''characterEncoding'' with the character set this collation belongs to. If neither this property nor the property ''characterEncoding'' is set:[CR]For Connector/J 8.0.25 and earlier, the driver will try to use the server default character set;[CR]For Connector/J 8.0.26 and later, the driver will use "utf8mb4" default collation.
ConnectionProperties.connectionLifecycleInterceptors=A comma-delimited list of classes that implement "com.mysql.cj.jdbc.interceptors.ConnectionLifecycleInterceptor" that should notified of connection lifecycle events (creation, destruction, commit, rollback, setting the current database and changing the autocommit mode) and potentially alter the execution of these commands. ConnectionLifecycleInterceptors are "stackable", more than one interceptor may be specified via the configuration property as a comma-delimited list, with the interceptors executed in order from left to right.
+ConnectionProperties.connectionPropertiesTransform=An implementation of com.mysql.cj.conf.ConnectionPropertiesTransform that the driver will use to modify URL properties passed to the driver before attempting a connection
+ConnectionProperties.connectionTimeZone=Configures the connection time zone which is used by Connector/J if conversion between the JVM default and a target time zone is needed when preserving instant temporal values.[CR]Accepts a geographic time zone name or a time zone offset from Greenwich/UTC, using a syntax ''java.time.ZoneId'' is able to parse, or one of the two logical values "LOCAL" and "SERVER". Default is "LOCAL". If set to an explicit time zone then it must be one that either the JVM or both the JVM and MySQL support. If set to "LOCAL" then the driver assumes that the connection time zone is the same as the JVM default time zone. If set to "SERVER" then the driver attempts to detect the session time zone from the values configured on the MySQL server session variables ''time_zone'' or ''system_time_zone''. The time zone detection and subsequent mapping to a Java time zone may fail due to several reasons, mostly because of time zone abbreviations being used, in which case an explicit time zone must be set or a different time zone must be configured on the server.[CR]This option itself does not set MySQL server session variable ''time_zone'' to the given value. To do that the ''forceConnectionTimeZoneToSession'' connection option must be set to "true".[CR]Please note that setting a value to ''connectionTimeZone'' in conjunction with ''forceConnectionTimeZoneToSession=false'' and ''preserveInstants=false'' has no effect since, in this case, neither this option is used to change the session time zone nor used for time zone conversions of time-based data.[CR]Former connection option ''serverTimezone'' is still valid as an alias of this one but may be deprecated in the future.[CR]See also ''forceConnectionTimeZoneToSession'' and ''preserveInstants'' for more details.
ConnectionProperties.connectTimeout=Timeout for socket connect (in milliseconds), with 0 being no timeout. Only works on JDK-1.4 or newer. Defaults to ''0''.
ConnectionProperties.continueBatchOnError=Should the driver continue processing batch commands if one statement fails. The JDBC spec allows either way (defaults to ''true'').
ConnectionProperties.createDatabaseIfNotExist=Creates the database given in the URL if it doesn''t yet exist. Assumes the configured user has permissions to create databases.
+ConnectionProperties.customCharsetMapping=A comma-delimited list of custom "charset:java encoding" pairs.[CR]In case the MySQL server is configured with custom character sets and ''detectCustomCollations=true'', Connector/J needs to know which Java character encoding to use for the data represented by these character sets. Example usage: ''customCharsetMapping=charset1:UTF-8,charset2:Cp1252''.
+ConnectionProperties.databaseTerm=MySQL uses the term "schema" as a synonym of the term "database," while Connector/J historically takes the JDBC term "catalog" as synonymous to "database". This property sets for Connector/J which of the JDBC terms "catalog" and "schema" is used in an application to refer to a database. The property takes one of the two values CATALOG or SCHEMA and uses it to determine (1) which Connection methods can be used to set/get the current database (e.g. setCatalog() or setSchema()?), (2) which arguments can be used within the various DatabaseMetaData methods to filter results (e.g. the catalog or schemaPattern argument of getColumns()?), and (3) which fields in the ResultSet returned by DatabaseMetaData methods contain the database identification information (i.e., the TABLE_CAT or TABLE_SCHEM field in the ResultSet returned by getTables()?).[CR]If databaseTerm=CATALOG, schemaPattern for searches are ignored and calls of schema methods (like setSchema() or get Schema()) become no-ops, and vice versa.
+ConnectionProperties.defaultAuthenticationPlugin=The default authentication plugin client-side protocol name or a fully qualified name of a class that implements the interface com.mysql.cj.protocol.AuthenticationPlugin. The specified authentication plugin must be either one of the built-in authentication plugins or one of the plugins listed in the property ''authenticationPlugins''. Additionally, the default authentication plugin cannot be disabled with the property ''disabledAuthenticationPlugins''. Neither an empty nor unknown plugin name or class can be set for this property.[CR]By default, Connector/J honors the server-side default authentication plugin, which is known after receiving the initial handshake packet, and falls back to this property's default value if that plugin cannot be used. However, when a value is explicitly provided to this property, Connector/J then overrides the server-side default authentication plugin and always tries first the plugin specified with this property.
ConnectionProperties.defaultFetchSize=The driver will call setFetchSize(n) with this value on all newly-created Statements
-ConnectionProperties.useServerPrepStmts=Use server-side prepared statements if the server supports them?
+ConnectionProperties.detectCustomCollations=Should the driver detect custom charsets/collations installed on server (true/false, defaults to ''false''). If this option set to ''true'' driver gets actual charsets/collations from server each time connection establishes. This could slow down connection initialization significantly.
+ConnectionProperties.disabledAuthenticationPlugins=Comma-delimited list of authentication plugins client-side protocol names or classes implementing the interface com.mysql.cj.protocol.AuthenticationPlugin. The authentication plugins listed will not be used for authenticating users and, if anyone of them is required during the authentication exchange, the connection fails. The default authentication plugin specified in the property ''defaultAuthenticationPlugin'' cannot be disabled.
+ConnectionProperties.disconnectOnExpiredPasswords=If "disconnectOnExpiredPasswords" is set to "false" and password is expired then server enters "sandbox" mode and sends ERR(08001, ER_MUST_CHANGE_PASSWORD) for all commands that are not needed to set a new password until a new password is set.
+ConnectionProperties.dnsSrv=Should the driver use the given host name to lookup for DNS SRV records and use the resulting list of hosts in a multi-host failover connection? Note that a single host name and no port must be provided when this option is enabled.
+ConnectionProperties.dontCheckOnDuplicateKeyUpdateInSQL=Stops checking if every INSERT statement contains the "ON DUPLICATE KEY UPDATE" clause. As a side effect, obtaining the statement''s generated keys information will return a list where normally it wouldn''t. Also be aware that, in this case, the list of generated keys returned may not be accurate. The effect of this property is canceled if set simultaneously with ''rewriteBatchedStatements=true''.
ConnectionProperties.dontTrackOpenResources=The JDBC specification requires the driver to automatically track and close resources, however if your application doesn''t do a good job of explicitly calling close() on statements or result sets, this can cause memory leakage. Setting this property to true relaxes this constraint, and can be more memory efficient for some applications. Also the automatic closing of the Statement and current ResultSet in Statement.closeOnCompletion() and Statement.getMoreResults ([Statement.CLOSE_CURRENT_RESULT | Statement.CLOSE_ALL_RESULTS]), respectively, ceases to happen. This property automatically sets holdResultsOpenOverStatementClose=true.
ConnectionProperties.dumpQueriesOnException=Should the driver dump the contents of the query sent to the server in the message for SQLExceptions?
ConnectionProperties.eliseSetAutoCommit=If using MySQL-4.1 or newer, should the driver only issue ''set autocommit=n'' queries when the server''s state doesn''t match the requested state by Connection.setAutoCommit(boolean)?
ConnectionProperties.emptyStringsConvertToZero=Should the driver allow conversions from empty string fields to numeric values of '''0''?
ConnectionProperties.emulateLocators=Should the driver emulate java.sql.Blobs with locators? With this feature enabled, the driver will delay loading the actual Blob data until the one of the retrieval methods (getInputStream(), getBytes(), and so forth) on the blob data stream has been accessed. For this to work, you must use a column alias with the value of the column to the actual name of the Blob. The feature also has the following restrictions: The SELECT that created the result set must reference only one table, the table must have a primary key; the SELECT must alias the original blob column name, specified as a string, to an alternate name; the SELECT must cover all columns that make up the primary key.
ConnectionProperties.emulateUnsupportedPstmts=Should the driver detect prepared statements that are not supported by the server, and replace them with client-side emulated versions?
+ConnectionProperties.enableEscapeProcessing=Sets the default escape processing behavior for Statement objects. The method Statement.setEscapeProcessing() can be used to specify the escape processing behavior for an individual Statement object. Default escape processing behavior in prepared statements must be defined with the property ''processEscapeCodesForPrepStmts''.
ConnectionProperties.enablePacketDebug=When enabled, a ring-buffer of ''packetDebugBufferSize'' packets will be kept, and dumped when exceptions are thrown in key areas in the driver''s code
ConnectionProperties.enableQueryTimeouts=When enabled, query timeouts set via Statement.setQueryTimeout() use a shared java.util.Timer instance for scheduling. Even if the timeout doesn''t expire before the query is processed, there will be memory used by the TimerTask for the given timeout which won''t be reclaimed until the time the timeout would have expired if it hadn''t been cancelled by the driver. High-load environments might want to consider disabling this functionality.
+ConnectionProperties.exceptionInterceptors=Comma-delimited list of classes that implement com.mysql.cj.exceptions.ExceptionInterceptor. These classes will be instantiated one per Connection instance, and all SQLExceptions thrown by the driver will be allowed to be intercepted by these interceptors, in a chained fashion, with the first class listed as the head of the chain.
ConnectionProperties.explainSlowQueries=If ''logSlowQueries'' is enabled, should the driver automatically issue an ''EXPLAIN'' on the server and send the results to the configured logger at a WARN level?
ConnectionProperties.failoverReadOnly=When failing over in autoReconnect mode, should the connection be set to ''read-only''?
+ConnectionProperties.fallbackToSystemKeyStore=Whether the absence of setting a value for ''clientCertificateKeyStoreUrl'' falls back to using the system-wide key store defined through the system properties ''javax.net.ssl.keyStore*''.
+ConnectionProperties.fallbackToSystemTrustStore=Whether the absence of setting a value for ''trustCertificateKeyStoreUrl'' falls back to using the system-wide default trust store or one defined through the system properties ''javax.net.ssl.trustStore*''.
+ConnectionProperties.forceConnectionTimeZoneToSession=If enabled, sets the time zone value determined by ''connectionTimeZone'' connection property to the current server session ''time_zone'' variable. If the time zone value is given as a geographical time zone, then Connector/J sets this value as-is in the server session, in which case the time zone system tables must be populated beforehand (consult the MySQL Server documentation for further details); but, if the value is given as an offset from Greenwich/UTC in any of the supported syntaxes, then the server session time zone is set as a numeric offset from UTC.[CR]With that no intermediate conversion between JVM default time zone and connection time zone is needed to store correct milliseconds value of instant Java objects such as java.sql.Timestamp or java.time.OffsetDateTime when stored in TIMESTAMP columns.[CR]Note that it also affects the result of MySQL functions such as ''NOW()'', ''CURTIME()'' or ''CURDATE()''.[CR]This option has no effect if used in conjunction with ''connectionTimeZone=SERVER'' since, in this case, the session is already set with the required time zone.[CR]See also ''connectionTimeZone'' and ''preserveInstants'' for more details.
+ConnectionProperties.functionsNeverReturnBlobs=Should the driver always treat data from functions returning BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?
ConnectionProperties.gatherPerfMetrics=Should the driver gather performance metrics, and report them via the configured logger every ''reportMetricsIntervalMillis'' milliseconds?
ConnectionProperties.generateSimpleParameterMetadata=Should the driver generate simplified parameter metadata for PreparedStatements when no metadata is available either because the server couldn''t support preparing the statement, or server-side prepared statements are disabled?
+ConnectionProperties.getProceduresReturnsFunctions=Pre-JDBC4 DatabaseMetaData API has only the getProcedures() and getProcedureColumns() methods, so they return metadata info for both stored procedures and functions. JDBC4 was extended with the getFunctions() and getFunctionColumns() methods and the expected behaviours of previous methods are not well defined. For JDBC4 and higher, default ''true'' value of the option means that calls of DatabaseMetaData.getProcedures() and DatabaseMetaData.getProcedureColumns() return metadata for both procedures and functions as before, keeping backward compatibility. Setting this property to ''false'' decouples Connector/J from its pre-JDBC4 behaviours for DatabaseMetaData.getProcedures() and DatabaseMetaData.getProcedureColumns(), forcing them to return metadata for procedures only.
+ConnectionProperties.ha.enableJMX=Enables JMX-based management of load-balanced connection groups, including live addition/removal of hosts from load-balancing pool. Enables JMX-based management of replication connection groups, including live replica promotion, addition of new replicas and removal of source or replica hosts from load-balanced source and replica connection pools.
ConnectionProperties.holdRSOpenOverStmtClose=Should the driver close result sets on Statement.close() as required by the JDBC specification?
ConnectionProperties.ignoreNonTxTables=Ignore non-transactional table warning for rollback? (defaults to ''false'').
ConnectionProperties.includeInnodbStatusInDeadlockExceptions=Include the output of "SHOW ENGINE INNODB STATUS" in exception messages when deadlock exceptions are detected?
@@ -828,50 +878,61 @@ ConnectionProperties.interactiveClient=Set the CLIENT_INTERACTIVE flag, which te
ConnectionProperties.jdbcCompliantTruncation=Should the driver throw java.sql.DataTruncation exceptions when data is truncated as is required by the JDBC specification when connected to a server that supports warnings (MySQL 4.1.0 and newer)? This property has no effect if the server sql-mode includes STRICT_TRANS_TABLES.
ConnectionProperties.largeRowSizeThreshold=What size result set row should the JDBC driver consider "large", and thus use a more memory-efficient way of representing the row internally?
ConnectionProperties.ldapServerHostname=When using MySQL''s LDAP pluggable authentication with GSSAPI/Kerberos authentication method, allows setting the LDAP service principal hostname as configured in the Kerberos KDC. If this property is not set, Connector/J takes the system property ''java.security.krb5.kdc'' and extracts the hostname (short name) from its value and uses it. If neither is set, the connection fails with an exception.
-ConnectionProperties.loadBalanceStrategy=If using a load-balanced connection to connect to SQL nodes in a MySQL Cluster/NDB configuration (by using the URL prefix "jdbc:mysql:loadbalance://"), which load balancing algorithm should the driver use: (1) "random" - the driver will pick a random host for each request. This tends to work better than round-robin, as the randomness will somewhat account for spreading loads where requests vary in response time, while round-robin can sometimes lead to overloaded nodes if there are variations in response times across the workload. (2) "bestResponseTime" - the driver will route the request to the host that had the best response time for the previous transaction. (3) "serverAffinity" - the driver initially attempts to enforce server affinity while still respecting and benefiting from the fault tolerance aspects of the load-balancing implementation. The server affinity ordered list is provided using the property ''serverAffinityOrder''. If none of the servers listed in the affinity list is responsive, the driver then refers to the "random" strategy to proceed with choosing the next server.
-ConnectionProperties.serverAffinityOrder=A comma separated list containing the host/port pairs that are to be used in load-balancing "serverAffinity" strategy. Only the sub-set of the hosts enumerated in the main hosts section in this URL will be used and they must be identical in case and type, i.e., can''t use an IP address in one place and the corresponding host name in the other.
+ConnectionProperties.loadBalanceAutoCommitStatementRegex=When load-balancing is enabled for auto-commit statements (via loadBalanceAutoCommitStatementThreshold), the statement counter will only increment when the SQL matches the regular expression. By default, every statement issued matches.
+ConnectionProperties.loadBalanceAutoCommitStatementThreshold=When auto-commit is enabled, the number of statements which should be executed before triggering load-balancing to rebalance. Default value of 0 causes load-balanced connections to only rebalance when exceptions are encountered, or auto-commit is disabled and transactions are explicitly committed or rolled back.
ConnectionProperties.loadBalanceBlocklistTimeout=Time in milliseconds between checks of servers which are unavailable, by controlling how long a server lives in the global blocklist.
-ConnectionProperties.loadBalancePingTimeout=Time in milliseconds to wait for ping response from each of load-balanced physical connections when using load-balanced Connection.
-ConnectionProperties.loadBalanceValidateConnectionOnSwapServer=Should the load-balanced Connection explicitly check whether the connection is live when swapping to a new physical connection at commit/rollback?
ConnectionProperties.loadBalanceConnectionGroup=Logical group of load-balanced connections within a classloader, used to manage different groups independently. If not specified, live management of load-balanced connections is disabled.
ConnectionProperties.loadBalanceExceptionChecker=Fully-qualified class name of custom exception checker. The class must implement com.mysql.cj.jdbc.ha.LoadBalanceExceptionChecker interface, and is used to inspect SQLExceptions and determine whether they should trigger fail-over to another host in a load-balanced deployment.
-ConnectionProperties.loadBalanceSQLStateFailover=Comma-delimited list of SQLState codes used by default load-balanced exception checker to determine whether a given SQLException should trigger failover. The SQLState of a given SQLException is evaluated to determine whether it begins with any value in the comma-delimited list.
-ConnectionProperties.loadBalanceSQLExceptionSubclassFailover=Comma-delimited list of classes/interfaces used by default load-balanced exception checker to determine whether a given SQLException should trigger failover. The comparison is done using Class.isInstance(SQLException) using the thrown SQLException.
-ConnectionProperties.ha.enableJMX=Enables JMX-based management of load-balanced connection groups, including live addition/removal of hosts from load-balancing pool. Enables JMX-based management of replication connection groups, including live replica promotion, addition of new replicas and removal of source or replica hosts from load-balanced source and replica connection pools.
ConnectionProperties.loadBalanceHostRemovalGracePeriod=Sets the grace period to wait for a host being removed from a load-balanced connection, to be released when it is currently the active host.
-ConnectionProperties.loadBalanceAutoCommitStatementThreshold=When auto-commit is enabled, the number of statements which should be executed before triggering load-balancing to rebalance. Default value of 0 causes load-balanced connections to only rebalance when exceptions are encountered, or auto-commit is disabled and transactions are explicitly committed or rolled back.
-ConnectionProperties.loadBalanceAutoCommitStatementRegex=When load-balancing is enabled for auto-commit statements (via loadBalanceAutoCommitStatementThreshold), the statement counter will only increment when the SQL matches the regular expression. By default, every statement issued matches.
+ConnectionProperties.loadBalancePingTimeout=Time in milliseconds to wait for ping response from each of load-balanced physical connections when using load-balanced Connection.
+ConnectionProperties.loadBalanceSQLExceptionSubclassFailover=Comma-delimited list of classes/interfaces used by default load-balanced exception checker to determine whether a given SQLException should trigger failover. The comparison is done using Class.isInstance(SQLException) using the thrown SQLException.
+ConnectionProperties.loadBalanceSQLStateFailover=Comma-delimited list of SQLState codes used by default load-balanced exception checker to determine whether a given SQLException should trigger failover. The SQLState of a given SQLException is evaluated to determine whether it begins with any value in the comma-delimited list.
+ConnectionProperties.loadBalanceStrategy=If using a load-balanced connection to connect to SQL nodes in a MySQL Cluster/NDB configuration (by using the URL prefix "jdbc:mysql:loadbalance://"), which load balancing algorithm should the driver use: (1) "random" - the driver will pick a random host for each request. This tends to work better than round-robin, as the randomness will somewhat account for spreading loads where requests vary in response time, while round-robin can sometimes lead to overloaded nodes if there are variations in response times across the workload. (2) "bestResponseTime" - the driver will route the request to the host that had the best response time for the previous transaction. (3) "serverAffinity" - the driver initially attempts to enforce server affinity while still respecting and benefiting from the fault tolerance aspects of the load-balancing implementation. The server affinity ordered list is provided using the property ''serverAffinityOrder''. If none of the servers listed in the affinity list is responsive, the driver then refers to the "random" strategy to proceed with choosing the next server.
+ConnectionProperties.loadBalanceValidateConnectionOnSwapServer=Should the load-balanced Connection explicitly check whether the connection is live when swapping to a new physical connection at commit/rollback?
+ConnectionProperties.loadDataLocal=Should the driver allow use of "LOAD DATA LOCAL INFILE ..."?[CR]Setting to "true" overrides whatever path is set in ''allowLoadLocalInfileInPath'', allowing uploading files from any location.
+ConnectionProperties.loadDataLocalInPath=Enables "LOAD DATA LOCAL INFILE ..." statements, but only allows loading files from the specified path. Files within sub-directories are also allowed, but relative paths or symlinks that fall outside this path are forbidden.
ConnectionProperties.localSocketAddress=Hostname or IP address given to explicitly configure the interface that the driver will bind the client side of the TCP/IP connection to when connecting.
ConnectionProperties.locatorFetchBufferSize=If ''emulateLocators'' is configured to ''true'', what size buffer should be used when fetching BLOB data for getBinaryInputStream?
ConnectionProperties.logger=The name of a class that implements \"{0}\" that will be used to log messages to. (default is \"{1}\", which logs to STDERR)
ConnectionProperties.logSlowQueries=Should queries that take longer than ''slowQueryThresholdMillis'' or detected by the ''autoSlowLog'' monitoring be reported to the registered ''profilerEventHandler''?
ConnectionProperties.logXaCommands=Should the driver log XA commands sent by MysqlXaConnection to the server, at the DEBUG level of logging?
ConnectionProperties.maintainTimeStats=Should the driver maintain various internal timers to enable idle time calculations as well as more verbose error messages when the connection to the server fails? Setting this property to false removes at least two calls to System.getCurrentTimeMillis() per query.
+ConnectionProperties.maxAllowedPacket=Maximum allowed packet size to send to server. If not set, the value of system variable ''max_allowed_packet'' will be used to initialize this upon connecting. This value will not take effect if set larger than the value of ''max_allowed_packet''. Also, due to an internal dependency with the property "blobSendChunkSize", this setting has a minimum value of "8203" if "useServerPrepStmts" is set to "true".
ConnectionProperties.maxQuerySizeToLog=Controls the maximum length of the part of a query that will get logged when profiling or tracing
ConnectionProperties.maxReconnects=Maximum number of reconnects to attempt if autoReconnect is true, default is ''3''.
ConnectionProperties.maxRows=The maximum number of rows to return (0, the default means return all rows).
-ConnectionProperties.allVersions=all versions
ConnectionProperties.metadataCacheSize=The number of queries to cache ResultSetMetadata for if cacheResultSetMetaData is set to ''true'' (default 50)
ConnectionProperties.netTimeoutForStreamingResults=What value should the driver automatically set the server setting ''net_write_timeout'' to when the streaming result sets feature is in use? (value has unit of seconds, the value ''0'' means the driver will not try and adjust this value)
ConnectionProperties.noAccessToProcedureBodies=When determining procedure parameter types for CallableStatements, and the connected user can''t access procedure bodies through "SHOW CREATE PROCEDURE" or select on mysql.proc should the driver instead create basic metadata (all parameters reported as INOUT VARCHARs) instead of throwing an exception?
ConnectionProperties.noDatetimeStringSync=Don''t ensure that ResultSet.getDatetimeType().toString().equals(ResultSet.getString())
-ConnectionProperties.cacheDefaultTimeZone=Caches client's default time zone. This results in better performance when dealing with time zone conversions in Date and Time data types, however it won't be aware of time zone changes if they happen at runtime.
ConnectionProperties.nullCatalogMeansCurrent=When DatabaseMetadata methods ask for a ''catalog'' or ''schema'' parameter, does the value null mean use the current database? See also property ''databaseTerm''.
-ConnectionProperties.databaseTerm=MySQL uses the term "schema" as a synonym of the term "database," while Connector/J historically takes the JDBC term "catalog" as synonymous to "database". This property sets for Connector/J which of the JDBC terms "catalog" and "schema" is used in an application to refer to a database. The property takes one of the two values CATALOG or SCHEMA and uses it to determine (1) which Connection methods can be used to set/get the current database (e.g. setCatalog() or setSchema()?), (2) which arguments can be used within the various DatabaseMetaData methods to filter results (e.g. the catalog or schemaPattern argument of getColumns()?), and (3) which fields in the ResultSet returned by DatabaseMetaData methods contain the database identification information (i.e., the TABLE_CAT or TABLE_SCHEM field in the ResultSet returned by getTables()?).[CR]If databaseTerm=CATALOG, schemaPattern for searches are ignored and calls of schema methods (like setSchema() or get Schema()) become no-ops, and vice versa.
+ConnectionProperties.ociConfigFile=The location of the OCI configuration file as required by the OCI SDK for Java. Default value is "~/.oci/config" for Unix-like systems and "%HOMEDRIVE%%HOMEPATH%.oci\\config" for Windows.
+ConnectionProperties.overrideSupportsIEF=Should the driver return "true" for DatabaseMetaData.supportsIntegrityEnhancementFacility() even if the database doesn''t support it to workaround applications that require this method to return "true" to signal support of foreign keys, even though the SQL specification states that this facility contains much more than just foreign key support (one such application being OpenOffice)?
ConnectionProperties.packetDebugBufferSize=The maximum number of packets to retain when ''enablePacketDebug'' is true
ConnectionProperties.padCharsWithSpace=If a result set column has the CHAR type and the value does not fill the amount of characters specified in the DDL for the column, should the driver pad the remaining characters with space (for ANSI compliance)?
ConnectionProperties.paranoid=Take measures to prevent exposure sensitive information in error messages and clear data structures holding sensitive data when possible? (defaults to ''false'')
+ConnectionProperties.parseInfoCacheFactory=Name of a class implementing com.mysql.cj.CacheAdapterFactory, which will be used to create caches for the parsed representation of client-side prepared statements.
+ConnectionProperties.Password=The password to use when connecting.
+ConnectionProperties.Password1=The password to use in the first phase of a Multi-Factor Authentication workflow. It is a synonym of the connection property 'password' and can also be set with user credentials in the connection string.
+ConnectionProperties.Password2=The password to use in the second phase of a Multi-Factor Authentication workflow.
+ConnectionProperties.Password3=The password to use in the third phase of a Multi-Factor Authentication workflow.
+ConnectionProperties.passwordCharacterEncoding=Instructs the server to use the default character set for the specified Java encoding during the authentication phase. If this property is not set, Connector/J falls back to the collation name specified in the property ''connectionCollation'' or to the Java encoding specified in the property ''characterEncoding'', in that order of priority. The "utf8mb4" default collation is used if none of the properties is set.
ConnectionProperties.pedantic=Follow the JDBC spec to the letter.
ConnectionProperties.pinGlobalTxToPhysicalConnection=When using XAConnections, should the driver ensure that operations on a given XID are always routed to the same physical connection? This allows the XAConnection to support "XA START ... JOIN" after "XA END" has been called
ConnectionProperties.populateInsertRowWithDefaultValues=When using ResultSets that are CONCUR_UPDATABLE, should the driver pre-populate the "insert" row with default values from the DDL for the table used in the query so those values are immediately available for ResultSet accessors? This functionality requires a call to the database for metadata each time a result set of this type is created. If disabled (the default), the default values will be populated by the an internal call to refreshRow() which pulls back default values and/or values changed by triggers.
ConnectionProperties.prepStmtCacheSize=If prepared statement caching is enabled, how many prepared statements should be cached?
ConnectionProperties.prepStmtCacheSqlLimit=If prepared statement caching is enabled, what''s the largest SQL the driver will cache the parsing for?
+ConnectionProperties.preserveInstants=If enabled, Connector/J does its best to preserve the instant point on the time-line for Java instant-based objects such as java.sql.Timestamp or java.time.OffsetDateTime instead of their original visual form. Otherwise, the driver always uses the JVM default time zone for rendering the values it sends to the server and for constructing the Java objects from the fetched data.[CR]MySQL uses implied time zone conversion for TIMESTAMP values: they are converted from the session time zone to UTC for storage, and back from UTC to the session time zone for retrieval. So, to store the correct correct UTC value internally, the driver converts the value from the original time zone to the session time zone before sending to the server. On retrieval, Connector/J converts the received value from the session time zone to the JVM default one.[CR]When storing, the conversion is performed only if the target SQLType, either the explicit one or the default one, is TIMESTAMP. When retrieving, the conversion is performed only if the source column has the TIMESTAMP, DATETIME or character type and the target class is an instant-based one, like java.sql.Timestamp or java.time.OffsetDateTime.[CR]Note that this option has no effect if used in conjunction with ''connectionTimeZone=LOCAL'' since, in this case, the source and target time zones are the same. Though, in this case, it's still possible to store a correct instant value if set ''forceConnectionTimeZoneToSession=true''.[CR]See also ''connectionTimeZone'' and ''forceConnectionTimeZoneToSession'' for more details.
ConnectionProperties.processEscapeCodesForPrepStmts=Should the driver process escape codes in queries that are prepared? Default escape processing behavior in non-prepared statements must be defined with the property ''enableEscapeProcessing''.
ConnectionProperties.profilerEventHandler=Name of a class that implements the interface com.mysql.cj.log.ProfilerEventHandler that will be used to handle profiling/tracing events.
ConnectionProperties.profileSQL=Trace queries and their execution/fetch times to the configured ''profilerEventHandler''
-ConnectionProperties.connectionPropertiesTransform=An implementation of com.mysql.cj.conf.ConnectionPropertiesTransform that the driver will use to modify URL properties passed to the driver before attempting a connection
ConnectionProperties.queriesBeforeRetrySource=Number of queries to issue before falling back to the primary host when failed over (when using multi-host failover). Whichever condition is met first, ''queriesBeforeRetrySource'' or ''secondsBeforeRetrySource'' will cause an attempt to be made to reconnect to the primary host. Setting both properties to 0 disables the automatic fall back to the primary host at transaction boundaries. Defaults to 50.
+ConnectionProperties.queryInterceptors=A comma-delimited list of classes that implement "com.mysql.cj.interceptors.QueryInterceptor" that should be placed "in between" query execution to influence the results. QueryInterceptors are "chainable", the results returned by the "current" interceptor will be passed on to the next in in the chain, from left-to-right order, as specified in this property.
+ConnectionProperties.queryTimeoutKillsConnection=If the timeout given in Statement.setQueryTimeout() expires, should the driver forcibly abort the Connection instead of attempting to abort the query?
+ConnectionProperties.readFromSourceWhenNoReplicas=Replication-aware connections distribute load by using the source hosts when in read/write state and by using the replica hosts when in read-only state. If, when setting the connection to read-only state, none of the replica hosts are available, an SQLException is thrown back. Setting this property to ''true'' allows to fail over to the source hosts, while setting the connection state to read-only, when no replica hosts are available at switch instant.
+ConnectionProperties.readOnlyPropagatesToServer=Should the driver issue appropriate statements to implicitly set the transaction access mode on server side when Connection.setReadOnly() is called? Setting this property to ''true'' enables InnoDB read-only potential optimizations but also requires an extra roundtrip to set the right transaction state. Even if this property is set to ''false'', the driver will do its best effort to prevent the execution of database-state-changing queries. Requires minimum of MySQL 5.6.
ConnectionProperties.reconnectAtTxEnd=If autoReconnect is set to true, should the driver attempt reconnections at the end of every transaction?
+ConnectionProperties.replicationConnectionGroup=Logical group of replication connections within a classloader, used to manage different groups independently. If not specified, live management of replication connections is disabled.
ConnectionProperties.reportMetricsIntervalMillis=If ''gatherPerfMetrics'' is enabled, how often should they be logged (in ms)?
ConnectionProperties.requireSSL=For 8.0.12 and earlier: Require server support of SSL connection if useSSL=true? (defaults to ''false'').[CR] For 8.0.13 and later: DEPRECATED. See sslMode property description for details.
ConnectionProperties.resourceId=A globally unique name that identifies the resource that this datasource or connection is connected to, used for XAResource.isSameRM() when the driver can''t determine this value based on hostnames used in the URL
@@ -879,13 +940,15 @@ ConnectionProperties.resultSetSizeThreshold=If ''useUsageAdvisor'' is true, how
ConnectionProperties.retriesAllDown=When using loadbalancing or failover, the number of times the driver should cycle through available hosts, attempting to connect. Between cycles, the driver will pause for 250ms if no servers are available.
ConnectionProperties.rewriteBatchedStatements=Should the driver use multiqueries (regardless of the setting of "allowMultiQueries") as well as rewriting of prepared statements for INSERT into multi-value inserts when executeBatch() is called? Notice that this has the potential for SQL injection if using plain java.sql.Statements and your code doesn''t sanitize input correctly. Notice that for prepared statements, server-side prepared statements can not currently take advantage of this rewrite option, and that if you don''t specify stream lengths when using PreparedStatement.set*Stream(), the driver won''t be able to determine the optimum number of parameters per batch and you might receive an error from the driver that the resultant packet is too large. Statement.getGeneratedKeys() for these rewritten statements only works when the entire batch includes INSERT statements. Please be aware using rewriteBatchedStatements=true with INSERT .. ON DUPLICATE KEY UPDATE that for rewritten statement server returns only one value as sum of all affected (or found) rows in batch and it isn''t possible to map it correctly to initial statements; in this case driver returns 0 as a result of each batch statement if total count was 0, and the Statement.SUCCESS_NO_INFO as a result of each batch statement if total count was > 0.
ConnectionProperties.rollbackOnPooledClose=Should the driver issue a rollback() when the logical connection in a pool is closed?
+ConnectionProperties.scrollTolerantForwardOnly=Should the driver contradict the JDBC API and tolerate and support backward and absolute cursor movement on result sets of type ''ResultSet.TYPE_FORWARD_ONLY''?[CR]Regardless of this setting, cursor-based and row streaming result sets cannot be navigated in the prohibited directions.
ConnectionProperties.secondsBeforeRetrySource=How long should the driver wait, when failed over, before attempting to reconnect to the primary host? Whichever condition is met first, ''queriesBeforeRetrySource'' or ''secondsBeforeRetrySource'' will cause an attempt to be made to reconnect to the source host. Setting both properties to 0 disables the automatic fall back to the primary host at transaction boundaries. Time in seconds, defaults to 30
-ConnectionProperties.selfDestructOnPingSecondsLifetime=If set to a non-zero value, the driver will close the connection and report failure when Connection.ping() or Connection.isValid(int) is called if the connection''s lifetime exceeds this value (in milliseconds).
ConnectionProperties.selfDestructOnPingMaxOperations=If set to a non-zero value, the driver will report close the connection and report failure when Connection.ping() or Connection.isValid(int) is called if the connection''s count of commands sent to the server exceeds this value.
-ConnectionProperties.connectionTimeZone=Configures the connection time zone which is used by Connector/J if conversion between the JVM default and a target time zone is needed when preserving instant temporal values.[CR]Accepts a geographic time zone name or a time zone offset from Greenwich/UTC, using a syntax ''java.time.ZoneId'' is able to parse, or one of the two logical values "LOCAL" and "SERVER". Default is "LOCAL". If set to an explicit time zone then it must be one that either the JVM or both the JVM and MySQL support. If set to "LOCAL" then the driver assumes that the connection time zone is the same as the JVM default time zone. If set to "SERVER" then the driver attempts to detect the session time zone from the values configured on the MySQL server session variables ''time_zone'' or ''system_time_zone''. The time zone detection and subsequent mapping to a Java time zone may fail due to several reasons, mostly because of time zone abbreviations being used, in which case an explicit time zone must be set or a different time zone must be configured on the server.[CR]This option itself does not set MySQL server session variable ''time_zone'' to the given value. To do that the ''forceConnectionTimeZoneToSession'' connection option must be set to "true".[CR]Please note that setting a value to ''connectionTimeZone'' in conjunction with ''forceConnectionTimeZoneToSession=false'' and ''preserveInstants=false'' has no effect since, in this case, neither this option is used to change the session time zone nor used for time zone conversions of time-based data.[CR]Former connection option ''serverTimezone'' is still valid as an alias of this one but may be deprecated in the future.[CR]See also ''forceConnectionTimeZoneToSession'' and ''preserveInstants'' for more details.
-ConnectionProperties.forceConnectionTimeZoneToSession=If enabled, sets the time zone value determined by ''connectionTimeZone'' connection property to the current server session ''time_zone'' variable. If the time zone value is given as a geographical time zone, then Connector/J sets this value as-is in the server session, in which case the time zone system tables must be populated beforehand (consult the MySQL Server documentation for further details); but, if the value is given as an offset from Greenwich/UTC in any of the supported syntaxes, then the server session time zone is set as a numeric offset from UTC.[CR]With that no intermediate conversion between JVM default time zone and connection time zone is needed to store correct milliseconds value of instant Java objects such as java.sql.Timestamp or java.time.OffsetDateTime when stored in TIMESTAMP columns.[CR]Note that it also affects the result of MySQL functions such as ''NOW()'', ''CURTIME()'' or ''CURDATE()''.[CR]This option has no effect if used in conjunction with ''connectionTimeZone=SERVER'' since, in this case, the session is already set with the required time zone.[CR]See also ''connectionTimeZone'' and ''preserveInstants'' for more details.
-ConnectionProperties.preserveInstants=If enabled, Connector/J does its best to preserve the instant point on the time-line for Java instant-based objects such as java.sql.Timestamp or java.time.OffsetDateTime instead of their original visual form. Otherwise, the driver always uses the JVM default time zone for rendering the values it sends to the server and for constructing the Java objects from the fetched data.[CR]MySQL uses implied time zone conversion for TIMESTAMP values: they are converted from the session time zone to UTC for storage, and back from UTC to the session time zone for retrieval. So, to store the correct correct UTC value internally, the driver converts the value from the original time zone to the session time zone before sending to the server. On retrieval, Connector/J converts the received value from the session time zone to the JVM default one.[CR]When storing, the conversion is performed only if the target SQLType, either the explicit one or the default one, is TIMESTAMP. When retrieving, the conversion is performed only if the source column has the TIMESTAMP, DATETIME or character type and the target class is an instant-based one, like java.sql.Timestamp or java.time.OffsetDateTime.[CR]Note that this option has no effect if used in conjunction with ''connectionTimeZone=LOCAL'' since, in this case, the source and target time zones are the same. Though, in this case, it's still possible to store a correct instant value if set ''forceConnectionTimeZoneToSession=true''.[CR]See also ''connectionTimeZone'' and ''forceConnectionTimeZoneToSession'' for more details.
-ConnectionProperties.scrollTolerantForwardOnly=Should the driver contradict the JDBC API and tolerate and support backward and absolute cursor movement on result sets of type ''ResultSet.TYPE_FORWARD_ONLY''?[CR]Regardless of this setting, cursor-based and row streaming result sets cannot be navigated in the prohibited directions.
+ConnectionProperties.selfDestructOnPingSecondsLifetime=If set to a non-zero value, the driver will close the connection and report failure when Connection.ping() or Connection.isValid(int) is called if the connection''s lifetime exceeds this value (in milliseconds).
+ConnectionProperties.sendFractionalSeconds=If set to "false", the fractional seconds will always be truncated before sending any data to the server. This option applies only to prepared statements, callable statements or updatable result sets.
+ConnectionProperties.sendFractionalSecondsForTime=If set to "false", the fractional seconds of java.sql.Time will be ignored as required by JDBC specification. If set to "true", it's value is rendered with fractional seconds allowing to store milliseconds into MySQL TIME column. This option applies only to prepared statements, callable statements or updatable result sets. It has no effect if sendFractionalSeconds=false.
+ConnectionProperties.serverAffinityOrder=A comma separated list containing the host/port pairs that are to be used in load-balancing "serverAffinity" strategy. Only the sub-set of the hosts enumerated in the main hosts section in this URL will be used and they must be identical in case and type, i.e., can''t use an IP address in one place and the corresponding host name in the other.
+ConnectionProperties.serverConfigCacheFactory=Name of a class implementing com.mysql.cj.CacheAdapterFactory>, which will be used to create caches for MySQL server configuration values
+ConnectionProperties.serverRSAPublicKeyFile=File path to the server RSA public key file for sha256_password authentication. If not specified, the public key will be retrieved from the server.
ConnectionProperties.sessionVariables=A comma or semicolon separated list of name=value pairs to be sent as SET [SESSION] ... to the server when the driver connects.
ConnectionProperties.slowQueryThresholdMillis=If ''logSlowQueries'' is enabled, how long should a query take (in ms) before it is logged as slow?
ConnectionProperties.slowQueryThresholdNanos=If ''logSlowQueries'' is enabled, ''useNanosForElapsedTime'' is set to true, and this property is set to a non-zero value, the driver will use this threshold (in nanosecond units) to determine if a query was slow.
@@ -893,18 +956,26 @@ ConnectionProperties.socketFactory=The name of the class that the driver should
ConnectionProperties.socketTimeout=Timeout (in milliseconds) on network socket operations (0, the default means no timeout).
ConnectionProperties.socksProxyHost=Name or IP address of SOCKS host to connect through.
ConnectionProperties.socksProxyPort=Port of SOCKS server.
-ConnectionProperties.queryInterceptors=A comma-delimited list of classes that implement "com.mysql.cj.interceptors.QueryInterceptor" that should be placed "in between" query execution to influence the results. QueryInterceptors are "chainable", the results returned by the "current" interceptor will be passed on to the next in in the chain, from left-to-right order, as specified in this property.
+ConnectionProperties.sslMode=By default, network connections are SSL encrypted; this property permits secure connections to be turned off, or a different levels of security to be chosen. The following values are allowed: "DISABLED" - Establish unencrypted connections; "PREFERRED" - (default) Establish encrypted connections if the server enabled them, otherwise fall back to unencrypted connections; "REQUIRED" - Establish secure connections if the server enabled them, fail otherwise; "VERIFY_CA" - Like "REQUIRED" but additionally verify the server TLS certificate against the configured Certificate Authority (CA) certificates; "VERIFY_IDENTITY" - Like "VERIFY_CA", but additionally verify that the server certificate matches the host to which the connection is attempted.[CR] This property replaced the deprecated legacy properties "useSSL", "requireSSL", and "verifyServerCertificate", which are still accepted but translated into a value for "sslMode" if "sslMode" is not explicitly set: "useSSL=false" is translated to "sslMode=DISABLED"; '{'"useSSL=true", "requireSSL=false", "verifyServerCertificate=false"'}' is translated to "sslMode=PREFERRED"; '{'"useSSL=true", "requireSSL=true", "verifyServerCertificate=false"'}' is translated to "sslMode=REQUIRED"; '{'"useSSL=true" AND "verifyServerCertificate=true"'}' is translated to "sslMode=VERIFY_CA". There is no equivalent legacy settings for "sslMode=VERIFY_IDENTITY". Note that, for ALL server versions, the default setting of "sslMode" is "PREFERRED", and it is equivalent to the legacy settings of "useSSL=true", "requireSSL=false", and "verifyServerCertificate=false", which are different from their default settings for Connector/J 8.0.12 and earlier in some situations. Applications that continue to use the legacy properties and rely on their old default settings should be reviewed.[CR] The legacy properties are ignored if "sslMode" is set explicitly. If none of "sslMode" or "useSSL" is set explicitly, the default setting of "sslMode=PREFERRED" applies.
ConnectionProperties.strictUpdates=Should the driver do strict checking (all primary keys selected) of updatable result sets (true, false, defaults to ''true'')?
-ConnectionProperties.overrideSupportsIEF=Should the driver return "true" for DatabaseMetaData.supportsIntegrityEnhancementFacility() even if the database doesn''t support it to workaround applications that require this method to return "true" to signal support of foreign keys, even though the SQL specification states that this facility contains much more than just foreign key support (one such application being OpenOffice)?
-ConnectionProperties.tcpNoDelay=If connecting using TCP/IP, should the driver set SO_TCP_NODELAY (disabling the Nagle Algorithm)?
ConnectionProperties.tcpKeepAlive=If connecting using TCP/IP, should the driver set SO_KEEPALIVE?
+ConnectionProperties.tcpNoDelay=If connecting using TCP/IP, should the driver set SO_TCP_NODELAY (disabling the Nagle Algorithm)?
ConnectionProperties.tcpSoRcvBuf=If connecting using TCP/IP, should the driver set SO_RCV_BUF to the given value? The default value of ''0'', means use the platform default value for this property)
ConnectionProperties.tcpSoSndBuf=If connecting using TCP/IP, should the driver set SO_SND_BUF to the given value? The default value of ''0'', means use the platform default value for this property)
ConnectionProperties.tcpTrafficClass=If connecting using TCP/IP, should the driver set traffic class or type-of-service fields ?See the documentation for java.net.Socket.setTrafficClass() for more information.
ConnectionProperties.tinyInt1isBit=Should the driver treat the datatype TINYINT(1) as the BIT type (because the server silently converts BIT -> TINYINT(1) when creating tables)?
+ConnectionProperties.tlsCiphersuites=When establishing secure connections, overrides the cipher suites enabled for use on the underlying SSL sockets. This may be required when using external JSSE providers or to specify cipher suites compatible with both MySQL server and used JVM.
+ConnectionProperties.tlsVersions=List of TLS protocols to allow when establishing secure connections. Overrides the TLS protocols enabled in the underlying SSL sockets. This can be used to restrict connections to specific TLS versions and, by doing that, avoid TLS negotiation fallback. Allowed and default values are TLSv1.2, TLSv1.3.
ConnectionProperties.traceProtocol=Should the network protocol be logged at the TRACE level?
-ConnectionProperties.treatUtilDateAsTimestamp=Should the driver treat java.util.Date as a TIMESTAMP for the purposes of PreparedStatement.setObject()?
+ConnectionProperties.trackSessionState=Receive server session state changes on query results. These changes are accessible via MysqlConnection.getServerSessionStateController().
ConnectionProperties.transformedBitIsBoolean=If the driver converts TINYINT(1) to a different type, should it use BOOLEAN instead of BIT for future compatibility with MySQL-5.0, as MySQL-5.0 has a BIT type?
+ConnectionProperties.treatUtilDateAsTimestamp=Should the driver treat java.util.Date as a TIMESTAMP for the purposes of PreparedStatement.setObject()?
+ConnectionProperties.trustCertificateKeyStorePassword=Password for the trusted root certificates key store.
+ConnectionProperties.trustCertificateKeyStoreType=Key store type for trusted root certificates.[CR]NULL or empty means use the default, which is "JKS". Standard key store types supported by the JVM are "JKS" and "PKCS12", your environment may have more available depending on what security products are installed and available to the JVM.
+ConnectionProperties.trustCertificateKeyStoreUrl=URL for the trusted root certificates key store.[CR]If not specified, the property ''fallbackToSystemTrustStore'' determines if system-wide trust store is used.
+ConnectionProperties.ultraDevHack=Create PreparedStatements for prepareCall() when required, because UltraDev is broken and issues a prepareCall() for _all_ statements? (true/false, defaults to ''false'')
+ConnectionProperties.useAffectedRows=Don''t set the CLIENT_FOUND_ROWS flag when connecting to the server (not JDBC-compliant, will break most applications that rely on "found" rows vs. "affected rows" for DML statements), but does cause "correct" update counts from "INSERT ... ON DUPLICATE KEY UPDATE" statements to be returned by the server.
+ConnectionProperties.useColumnNamesInFindColumn=Prior to JDBC-4.0, the JDBC specification had a bug related to what could be given as a "column name" to ResultSet methods like findColumn(), or getters that took a String property. JDBC-4.0 clarified "column name" to mean the label, as given in an "AS" clause and returned by ResultSetMetaData.getColumnLabel(), and if no AS clause, the column name. Setting this property to "true" will give behavior that is congruent to JDBC-3.0 and earlier versions of the JDBC specification, but which because of the specification bug could give unexpected results. This property is preferred over "useOldAliasMetadataBehavior" unless you need the specific behavior that it provides with respect to ResultSetMetadata.
ConnectionProperties.useCompression=Use zlib compression when communicating with the server (true/false)?
ConnectionProperties.useConfigs=Load the comma-delimited list of configuration properties before parsing the URL or applying user-specified properties. These configurations are explained in the ''Configurations'' of the documentation.
ConnectionProperties.useCursorFetch=Should the driver use cursor-based fetching to retrieve rows? If set to "true" and "defaultFetchSize" > 0 (or setFetchSize() > 0 is called on a statement) then the cursor-based result set will be used. Please note that "useServerPrepStmts" is automatically set to "true" in this case because cursor functionality is available only for server-side prepared statements.
@@ -916,56 +987,19 @@ ConnectionProperties.useNanosForElapsedTime=For profiling/debugging functionalit
ConnectionProperties.useOldAliasMetadataBehavior=Should the driver use the legacy behavior for "AS" clauses on columns and tables, and only return aliases (if any) for ResultSetMetaData.getColumnName() or ResultSetMetaData.getTableName() rather than the original column/table name? In 5.0.x, the default value was true.
ConnectionProperties.useOnlyServerErrorMessages=Don''t prepend ''standard'' SQLState error messages to error messages returned by the server.
ConnectionProperties.useReadAheadInput=Use newer, optimized non-blocking, buffered input stream when reading from the server?
+ConnectionProperties.Username=The user to connect as
+ConnectionProperties.useServerPrepStmts=Use server-side prepared statements if the server supports them?
ConnectionProperties.useSqlStateCodes=Use SQL Standard state codes instead of ''legacy'' X/Open/SQL state codes (true/false), default is ''true''
ConnectionProperties.useSSL=For 8.0.12 and earlier: Use SSL when communicating with the server (true/false), default is ''true'' when connecting to MySQL 5.5.45+, 5.6.26+ or 5.7.6+, otherwise default is ''false''.[CR] For 8.0.13 and later: Default is ''true''. DEPRECATED. See sslMode property description for details.
ConnectionProperties.useStreamLengthsInPrepStmts=Honor stream length parameter in PreparedStatement/ResultSet.setXXXStream() method calls (true/false, defaults to ''true'')?
-ConnectionProperties.ultraDevHack=Create PreparedStatements for prepareCall() when required, because UltraDev is broken and issues a prepareCall() for _all_ statements? (true/false, defaults to ''false'')
ConnectionProperties.useUnbufferedInput=Don''t use BufferedInputStream for reading data from the server
ConnectionProperties.useUsageAdvisor=Should the driver issue ''usage'' warnings advising proper and efficient usage of JDBC and MySQL Connector/J to the ''profilerEventHandler''?
ConnectionProperties.verifyServerCertificate=For 8.0.12 and earlier: If "useSSL" is set to "true", should the driver verify the server''s certificate? When using this feature, the key store parameters should be specified by the "clientCertificateKeyStore*" properties, rather than system properties. Default is ''false'' when connecting to MySQL 5.5.45+, 5.6.26+ or 5.7.6+ and "useSSL" was not explicitly set to "true". Otherwise default is ''true''.[CR] For 8.0.13 and later: Default is ''false''. DEPRECATED. See sslMode property description for details.
ConnectionProperties.yearIsDateType=Should the JDBC driver treat the MySQL type "YEAR" as a java.sql.Date, or as a SHORT?
ConnectionProperties.zeroDateTimeBehavior=What should happen when the driver encounters DATETIME values that are composed entirely of zeros (used by MySQL to represent invalid dates)? Valid values are \"{0}\", \"{1}\" and \"{2}\".
-ConnectionProperties.clientCertificateKeyStoreUrl=URL for the client certificate KeyStore[CR]If not specified, the property ''fallbackToSystemKeyStore'' determines if system-wide key store is used.
-ConnectionProperties.clientCertificateKeyStoreType=Key store type for client certificates.[CR]NULL or empty means use the default, which is "JKS". Standard key store types supported by the JVM are "JKS" and "PKCS12", your environment may have more available depending on what security products are installed and available to the JVM.
-ConnectionProperties.clientCertificateKeyStorePassword=Password for the client certificates key store.
-ConnectionProperties.fallbackToSystemKeyStore=Whether the absence of setting a value for ''clientCertificateKeyStoreUrl'' falls back to using the system-wide key store defined through the system properties ''javax.net.ssl.keyStore*''.
-ConnectionProperties.trustCertificateKeyStoreUrl=URL for the trusted root certificates key store.[CR]If not specified, the property ''fallbackToSystemTrustStore'' determines if system-wide trust store is used.
-ConnectionProperties.trustCertificateKeyStoreType=Key store type for trusted root certificates.[CR]NULL or empty means use the default, which is "JKS". Standard key store types supported by the JVM are "JKS" and "PKCS12", your environment may have more available depending on what security products are installed and available to the JVM.
-ConnectionProperties.trustCertificateKeyStorePassword=Password for the trusted root certificates key store.
-ConnectionProperties.fallbackToSystemTrustStore=Whether the absence of setting a value for ''trustCertificateKeyStoreUrl'' falls back to using the system-wide default trust store or one defined through the system properties ''javax.net.ssl.trustStore*''.
-ConnectionProperties.serverRSAPublicKeyFile=File path to the server RSA public key file for sha256_password authentication. If not specified, the public key will be retrieved from the server.
-ConnectionProperties.allowPublicKeyRetrieval=Allows special handshake round-trip to get an RSA public key directly from server.
-ConnectionProperties.Username=The user to connect as
-ConnectionProperties.Password=The password to use when connecting
-ConnectionProperties.sendFractionalSeconds=If set to "false", the fractional seconds will always be truncated before sending any data to the server. This option applies only to prepared statements, callable statements or updatable result sets.
-ConnectionProperties.sendFractionalSecondsForTime=If set to "false", the fractional seconds of java.sql.Time will be ignored as required by JDBC specification. If set to "true", it's value is rendered with fractional seconds allowing to store milliseconds into MySQL TIME column. This option applies only to prepared statements, callable statements or updatable result sets. It has no effect if sendFractionalSeconds=false.
-ConnectionProperties.useColumnNamesInFindColumn=Prior to JDBC-4.0, the JDBC specification had a bug related to what could be given as a "column name" to ResultSet methods like findColumn(), or getters that took a String property. JDBC-4.0 clarified "column name" to mean the label, as given in an "AS" clause and returned by ResultSetMetaData.getColumnLabel(), and if no AS clause, the column name. Setting this property to "true" will give behavior that is congruent to JDBC-3.0 and earlier versions of the JDBC specification, but which because of the specification bug could give unexpected results. This property is preferred over "useOldAliasMetadataBehavior" unless you need the specific behavior that it provides with respect to ResultSetMetadata.
-ConnectionProperties.useAffectedRows=Don''t set the CLIENT_FOUND_ROWS flag when connecting to the server (not JDBC-compliant, will break most applications that rely on "found" rows vs. "affected rows" for DML statements), but does cause "correct" update counts from "INSERT ... ON DUPLICATE KEY UPDATE" statements to be returned by the server.
-ConnectionProperties.passwordCharacterEncoding=What character encoding is used for passwords? Leaving this set to the default value (null), uses the value set in "characterEncoding" if there is one, otherwise uses UTF-8 as default encoding. If the password contains non-ASCII characters, the password encoding must match what server encoding was set to when the password was created. For passwords in other character encodings, the encoding will have to be specified with this property (or with "characterEncoding"), as it''s not possible for the driver to auto-detect this.
-ConnectionProperties.exceptionInterceptors=Comma-delimited list of classes that implement com.mysql.cj.exceptions.ExceptionInterceptor. These classes will be instantiated one per Connection instance, and all SQLExceptions thrown by the driver will be allowed to be intercepted by these interceptors, in a chained fashion, with the first class listed as the head of the chain.
-ConnectionProperties.maxAllowedPacket=Maximum allowed packet size to send to server. If not set, the value of system variable ''max_allowed_packet'' will be used to initialize this upon connecting. This value will not take effect if set larger than the value of ''max_allowed_packet''. Also, due to an internal dependency with the property "blobSendChunkSize", this setting has a minimum value of "8203" if "useServerPrepStmts" is set to "true".
-ConnectionProperties.queryTimeoutKillsConnection=If the timeout given in Statement.setQueryTimeout() expires, should the driver forcibly abort the Connection instead of attempting to abort the query?
-ConnectionProperties.authenticationPlugins=Comma-delimited list of classes that implement the interface com.mysql.cj.protocol.AuthenticationPlugin. These plugins will be loaded at connection initialization and can be used together with their sever-side counterparts for authenticating users, unless they are also disabled in the connection property ''disabledAuthenticationPlugins''.
-ConnectionProperties.disabledAuthenticationPlugins=Comma-delimited list of authentication plugins client-side protocol names or classes implementing the interface com.mysql.cj.protocol.AuthenticationPlugin. The authentication plugins listed will not be used for authenticating users and, if anyone of them is required during the authentication exchange, the connection fails. The default authentication plugin specified in the property ''defaultAuthenticationPlugin'' cannot be disabled.
-ConnectionProperties.defaultAuthenticationPlugin=The default authentication plugin client-side protocol name or a fully qualified name of a class that implements the interface com.mysql.cj.protocol.AuthenticationPlugin. The specified authentication plugin must be either one of the built-in authentication plugins or one of the plugins listed in the property ''authenticationPlugins''. Additionally, the default authentication plugin cannot be disabled with the property ''disabledAuthenticationPlugins''. Neither an empty nor unknown plugin name or class can be set for this property.[CR]By default, Connector/J honors the server-side default authentication plugin, which is known after receiving the initial handshake packet, and falls back to this property's default value if that plugin cannot be used. However, when a value is explicitly provided to this property, Connector/J then overrides the server-side default authentication plugin and always tries first the plugin specified with this property.
-ConnectionProperties.parseInfoCacheFactory=Name of a class implementing com.mysql.cj.CacheAdapterFactory, which will be used to create caches for the parsed representation of client-side prepared statements.
-ConnectionProperties.serverConfigCacheFactory=Name of a class implementing com.mysql.cj.CacheAdapterFactory>, which will be used to create caches for MySQL server configuration values
-ConnectionProperties.disconnectOnExpiredPasswords=If "disconnectOnExpiredPasswords" is set to "false" and password is expired then server enters "sandbox" mode and sends ERR(08001, ER_MUST_CHANGE_PASSWORD) for all commands that are not needed to set a new password until a new password is set.
-ConnectionProperties.connectionAttributes=A comma-delimited list of user-defined key:value pairs (in addition to standard MySQL-defined key:value pairs) to be passed to MySQL Server for display as connection attributes in the PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS table. Example usage: connectionAttributes=key1:value1,key2:value2 This functionality is available for use with MySQL Server version 5.6 or later only. Earlier versions of MySQL Server do not support connection attributes, causing this configuration option to be ignored. Setting connectionAttributes=none will cause connection attribute processing to be bypassed, for situations where Connection creation/initialization speed is critical.
-ConnectionProperties.getProceduresReturnsFunctions=Pre-JDBC4 DatabaseMetaData API has only the getProcedures() and getProcedureColumns() methods, so they return metadata info for both stored procedures and functions. JDBC4 was extended with the getFunctions() and getFunctionColumns() methods and the expected behaviours of previous methods are not well defined. For JDBC4 and higher, default ''true'' value of the option means that calls of DatabaseMetaData.getProcedures() and DatabaseMetaData.getProcedureColumns() return metadata for both procedures and functions as before, keeping backward compatibility. Setting this property to ''false'' decouples Connector/J from its pre-JDBC4 behaviours for DatabaseMetaData.getProcedures() and DatabaseMetaData.getProcedureColumns(), forcing them to return metadata for procedures only.
-ConnectionProperties.detectCustomCollations=Should the driver detect custom charsets/collations installed on server (true/false, defaults to ''false''). If this option set to ''true'' driver gets actual charsets/collations from server each time connection establishes. This could slow down connection initialization significantly.
-ConnectionProperties.dontCheckOnDuplicateKeyUpdateInSQL=Stops checking if every INSERT statement contains the "ON DUPLICATE KEY UPDATE" clause. As a side effect, obtaining the statement''s generated keys information will return a list where normally it wouldn''t. Also be aware that, in this case, the list of generated keys returned may not be accurate. The effect of this property is canceled if set simultaneously with ''rewriteBatchedStatements=true''.
-ConnectionProperties.readOnlyPropagatesToServer=Should the driver issue appropriate statements to implicitly set the transaction access mode on server side when Connection.setReadOnly() is called? Setting this property to ''true'' enables InnoDB read-only potential optimizations but also requires an extra roundtrip to set the right transaction state. Even if this property is set to ''false'', the driver will do its best effort to prevent the execution of database-state-changing queries. Requires minimum of MySQL 5.6.
-ConnectionProperties.enabledSSLCipherSuites=If "useSSL" is set to "true", overrides the cipher suites enabled for use on the underlying SSL sockets. This may be required when using external JSSE providers or to specify cipher suites compatible with both MySQL server and used JVM.
-ConnectionProperties.enabledTLSProtocols=If "useSSL" is set to "true", overrides the TLS protocols enabled for use on the underlying SSL sockets. This may be used to restrict connections to specific TLS versions.
-ConnectionProperties.enableEscapeProcessing=Sets the default escape processing behavior for Statement objects. The method Statement.setEscapeProcessing() can be used to specify the escape processing behavior for an individual Statement object. Default escape processing behavior in prepared statements must be defined with the property ''processEscapeCodesForPrepStmts''.
-ConnectionProperties.replicationConnectionGroup=Logical group of replication connections within a classloader, used to manage different groups independently. If not specified, live management of replication connections is disabled.
-ConnectionProperties.dnsSrv=Should the driver use the given host name to lookup for DNS SRV records and use the resulting list of hosts in a multi-host failover connection? Note that a single host name and no port must be provided when this option is enabled.
-ConnectionProperties.sslMode=By default, network connections are SSL encrypted; this property permits secure connections to be turned off, or a different levels of security to be chosen. The following values are allowed: "DISABLED" - Establish unencrypted connections; "PREFERRED" - (default) Establish encrypted connections if the server enabled them, otherwise fall back to unencrypted connections; "REQUIRED" - Establish secure connections if the server enabled them, fail otherwise; "VERIFY_CA" - Like "REQUIRED" but additionally verify the server TLS certificate against the configured Certificate Authority (CA) certificates; "VERIFY_IDENTITY" - Like "VERIFY_CA", but additionally verify that the server certificate matches the host to which the connection is attempted.[CR] This property replaced the deprecated legacy properties "useSSL", "requireSSL", and "verifyServerCertificate", which are still accepted but translated into a value for "sslMode" if "sslMode" is not explicitly set: "useSSL=false" is translated to "sslMode=DISABLED"; '{'"useSSL=true", "requireSSL=false", "verifyServerCertificate=false"'}' is translated to "sslMode=PREFERRED"; '{'"useSSL=true", "requireSSL=true", "verifyServerCertificate=false"'}' is translated to "sslMode=REQUIRED"; '{'"useSSL=true" AND "verifyServerCertificate=true"'}' is translated to "sslMode=VERIFY_CA". There is no equivalent legacy settings for "sslMode=VERIFY_IDENTITY". Note that, for ALL server versions, the default setting of "sslMode" is "PREFERRED", and it is equivalent to the legacy settings of "useSSL=true", "requireSSL=false", and "verifyServerCertificate=false", which are different from their default settings for Connector/J 8.0.12 and earlier in some situations. Applications that continue to use the legacy properties and rely on their old default settings should be reviewed.[CR] The legacy properties are ignored if "sslMode" is set explicitly. If none of "sslMode" or "useSSL" is set explicitly, the default setting of "sslMode=PREFERRED" applies.
-
ConnectionProperties.xdevapiSslMode=X DevAPI-specific SSL mode setting. If not specified, use ''sslMode''. Because the "PREFERRED" mode is not applicable to X Protocol, if ''xdevapi.ssl-mode'' is not set and ''sslMode'' is set to "PREFERRED", ''xdevapi.ssl-mode'' is set to "REQUIRED".
ConnectionProperties.xdevapiTlsCiphersuites=X DevAPI-specific property overriding the cipher suites enabled for use on the underlying SSL sockets. If not specified, the value of ''enabledSSLCipherSuites'' is used.
-ConnectionProperties.xdevapiTlsVersions=X DevAPI-specific property overriding the TLS protocols enabled for use on the underlying SSL sockets. If not specified, the value of ''enabledTLSProtocols'' is used.
+ConnectionProperties.xdevapiTlsVersions=X DevAPI-specific property that takes a list of TLS protocols to allow when creating secure sessions. Overrides the TLS protocols enabled in the underlying SSL socket. If not specified, then the value of ''tlsVersions'' is used instead. Allowed and default values are TLSv1.2, TLSv1.3.
ConnectionProperties.xdevapiSslKeyStoreUrl=X DevAPI-specific URL for the client certificate key store. If not specified, use ''clientCertificateKeyStoreUrl'' value.
ConnectionProperties.xdevapiSslKeyStoreType=X DevAPI-specific type of the client certificate key store. If not specified, use ''clientCertificateKeyStoreType'' value.
ConnectionProperties.xdevapiSslKeyStorePassword=X DevAPI-specific password for the client certificate key store. If not specified, use ''clientCertificateKeyStorePassword'' value.
@@ -975,13 +1009,12 @@ ConnectionProperties.xdevapiSslTrustStoreType=X DevAPI-specific type of the trus
ConnectionProperties.xdevapiSslTrustStorePassword=X DevAPI-specific password for the trusted CA certificates key store. If not specified, use ''trustCertificateKeyStorePassword'' value.
ConnectionProperties.xdevapiFallbackToSystemTrustStore=X DevAPI-specific switch to specify whether in the absence of a set value for ''xdevapi.ssl-truststore'' (or ''trustCertificateKeyStoreUrl''), Connector/J falls back to using the system-wide default trust store or one defined through the system properties ''javax.net.ssl.trustStore*''. If not specified, the value of ''fallbackToSystemTrustStore'' is used.
ConnectionProperties.auth=Authentication mechanism to use with the X Protocol. Allowed values are "SHA256_MEMORY", "MYSQL41", "PLAIN", and "EXTERNAL". Value is case insensitive. If the property is not set, the mechanism is chosen depending on the connection type: "PLAIN" is used for TLS connections and "SHA256_MEMORY" or "MYSQL41" is used for unencrypted connections.
-ConnectionProperties.xdevapiConnectTimeout=X DevAPI-specific timeout for socket connect (in milliseconds), with "0" being no timeout. Defaults to "10000". If ''xdevapi.connect-timeout'' is not set explicitly and ''connectTimeout'' is, ''xdevapi.connect-timeout'' takes up the value of ''connectTimeout''. If ''xdevapi.useAsyncProtocol=true'', both ''xdevapi.connect-timeout'' and ''connectTimeout'' are ignored.
+ConnectionProperties.xdevapiConnectTimeout=X DevAPI-specific timeout for socket connect (in milliseconds), with "0" being no timeout. Defaults to "10000". If ''xdevapi.connect-timeout'' is not set explicitly and ''connectTimeout'' is, ''xdevapi.connect-timeout'' takes up the value of ''connectTimeout''.
ConnectionProperties.xdevapiConnectionAttributes=An X DevAPI-specific comma-delimited list of user-defined key=value pairs (in addition to standard X Protocol-defined key=value pairs) to be passed to MySQL Server for display as connection attributes in PERFORMANCE_SCHEMA tables session_account_connect_attrs and session_connect_attrs. Example usage: xdevapi.connection-attributes=key1=value1,key2=value2 or xdevapi.connection-attributes=[key1=value1,key2=value2]. This functionality is available for use with MySQL Server version 8.0.16 or later only. Earlier versions of X Protocol do not support connection attributes, causing this configuration option to be ignored. For situations where Session creation/initialization speed is critical, setting xdevapi.connection-attributes=false will cause connection attribute processing to be bypassed.
ConnectionProperties.xdevapiDnsSrv=X DevAPI-specific option for instructing the driver use the given host name to lookup for DNS SRV records and use the resulting list of hosts in a multi-host failover connection. Note that a single host name and no port must be provided when this option is enabled.
ConnectionProperties.xdevapiCompression=X DevAPI-specific network traffic compression. This option accepts one of the three values: "PREFERRED", "REQUIRED", and "DISABLED". Setting this option to "PREFERRED" or "REQUIRED" enables compression algorithm negotiation between Connector and Server, and turns on compression of large X Protocol packets, as long as a consensus is reached between client and server regarding the compression algorithm to use. If a consensus cannot be reached, connection fails if the option is set to "REQUIRED" and continues without compression if the option is set to "PREFERRED". Setting this option as "DISABLED" skips the compression negotiation phase and forbids the interchange of compressed messages between client and server.
ConnectionProperties.xdevapiCompressionAlgorithms=A comma-delimited list of compression algorithms, each one identified by its name and operating mode (e.g. "lz4_message" -- consult the description for the MySQL global variable ''mysqlx_compression_algorithms'' for a list of supported and enabled algorithms), that defines the order and which algorithms will be attempted when negotiating connection compression with the server.[CR]The compression algorithm ''deflate_stream'' is supported natively. Additional compression algorithms require using third-party libraries and enabling them with the connection property ''xdevapi.compression-extensions''.[CR]This option is meaningful only when network traffic compression is enabled using the connection property ''xdevapi.compression''.[CR]As an alternative to the default algorithm names, that contain a reference to the compression operation mode, the aliases "zstd", "lz4", and "deflate" can be used instead of "zstd_stream", "lz4_message", and "deflate_stream".
ConnectionProperties.xdevapiCompressionExtensions=A comma-delimited list of triplets, with their elements delimited by colon, that enables the support for additional compression algorithms. Each triplet must contain: first, an algorithm name and operating mode (e.g. "lz4_message" -- consult the description for the MySQL global variable ''mysqlx_compression_algorithms'' for a list of supported and enabled algorithms); second, a fully-qualified class name of a class implementing the interface java.io.InputStream that will be used to inflate data compressed with the named algorithm; third, a fully-qualified class name of a class implementing the interface java.io.OutputStream that will be used to deflate data using the named algorithm. Along with this setting, the library containing implementations of the designated classes must be available in the application's class path.[CR]Any number of triplets defining compression algorithms and their inflater and deflater implementations can be provided but only the ones supported and enabled on the MySQL Server can be used.[CR]The compression algorithm ''deflate_stream'' is supported natively. Additional compression algorithms require using third-party libraries.[CR]This option is meaningful only when network traffic compression is enabled using the connection property ''xdevapi.compression''.[CR]As an alternative to the default algorithm names, that contain a reference to the compression operation mode, the aliases "zstd", "lz4", and "deflate" can be used instead of "zstd_stream", "lz4_message", and "deflate_stream".
-ConnectionProperties.useAsyncProtocol=For 8.0.21 and earlier: Use asynchronous variant of X Protocol.[CR]For 8.0.22 and later: DEPRECATED; has no effect.
ConnectionProperties.asyncResponseTimeout=For 8.0.21 and earlier: Timeout (in seconds) for getting server response via X Protocol.[CR]For 8.0.22 and later: DEPRECATED; has no effect.
ConnectionProperties.unknown=Property is not defined in Connector/J but used in connection URL.
diff --git a/src/main/resources/com/mysql/cj/TlsSettings.properties b/src/main/resources/com/mysql/cj/TlsSettings.properties
index 1e6847830..df6f68bab 100644
--- a/src/main/resources/com/mysql/cj/TlsSettings.properties
+++ b/src/main/resources/com/mysql/cj/TlsSettings.properties
@@ -1,4 +1,4 @@
-# Copyright (c) 2019, 2020, Oracle and/or its affiliates.
+# Copyright (c) 2019, 2021, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License, version 2.0, as published by the
@@ -27,84 +27,100 @@
# Mandatory TLS Ciphers
TLSCiphers.Mandatory=\
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\
+ ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\
+ ECDHE_RSA_WITH_AES_128_GCM_SHA256
# Approved TLS Ciphers
TLSCiphers.Approved=\
- TLS_AES_128_GCM_SHA256,\
- TLS_AES_256_GCM_SHA384,\
- TLS_CHACHA20_POLY1305_SHA256,\
- TLS_AES_128_CCM_SHA256,\
- TLS_AES_128_CCM_8_SHA256,\
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,\
- TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,\
- TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,\
- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,\
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,\
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,\
- TLS_DH_DSS_WITH_AES_128_GCM_SHA256,\
- TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,\
- TLS_DH_DSS_WITH_AES_256_GCM_SHA384,\
- TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,\
- TLS_DH_RSA_WITH_AES_128_GCM_SHA256,\
- TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,\
- TLS_DH_RSA_WITH_AES_256_GCM_SHA384,\
- TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+ AES_128_GCM_SHA256,\
+ AES_256_GCM_SHA384,\
+ CHACHA20_POLY1305_SHA256,\
+ AES_128_CCM_SHA256,\
+ AES_128_CCM_8_SHA256,\
+ ECDHE_RSA_WITH_AES_256_GCM_SHA384,\
+ DHE_RSA_WITH_AES_128_GCM_SHA256,\
+ DHE_DSS_WITH_AES_128_GCM_SHA256,\
+ DHE_DSS_WITH_AES_256_GCM_SHA384,\
+ DHE_RSA_WITH_AES_256_GCM_SHA384,\
+ ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,\
+ ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,\
+ ECDHE_ECDSA_WITH_AES_256_CCM,\
+ ECDHE_ECDSA_WITH_AES_128_CCM,\
+ DHE_RSA_WITH_AES_256_CCM,\
+ DHE_RSA_WITH_AES_128_CCM,\
+ DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,\
+ ECDHE_ECDSA_WITH_AES_256_CCM_8,\
+ ECDHE_ECDSA_WITH_AES_128_CCM_8,\
+ DHE_RSA_WITH_AES_256_CCM_8,\
+ DHE_RSA_WITH_AES_128_CCM_8
# Deprecated TLS Ciphers
TLSCiphers.Deprecated=\
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,\
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,\
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,\
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,\
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,\
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,\
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,\
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,\
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,\
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,\
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,\
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,\
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA,\
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA,\
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA,\
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA,\
- TLS_DH_RSA_WITH_AES_128_CBC_SHA256,\
- TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,\
- TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,\
- TLS_DH_RSA_WITH_AES_256_CBC_SHA256,\
- TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,\
- TLS_DH_DSS_WITH_AES_128_CBC_SHA256,\
- TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,\
- TLS_DH_DSS_WITH_AES_128_CBC_SHA,\
- TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,\
- TLS_DH_DSS_WITH_AES_256_CBC_SHA,\
- TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,\
- TLS_DH_DSS_WITH_AES_256_CBC_SHA256,\
- TLS_DH_RSA_WITH_AES_128_CBC_SHA,\
- TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,\
- TLS_DH_RSA_WITH_AES_256_CBC_SHA,\
- TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,\
- TLS_RSA_WITH_AES_128_GCM_SHA256,\
- TLS_RSA_WITH_AES_256_GCM_SHA384,\
- TLS_RSA_WITH_AES_128_CBC_SHA256,\
- TLS_RSA_WITH_AES_256_CBC_SHA256,\
- TLS_RSA_WITH_AES_128_CBC_SHA,\
- TLS_RSA_WITH_AES_256_CBC_SHA,\
- TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,\
- TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,\
- TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,\
- TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,\
- TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,\
- TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,\
- TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,\
- TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,\
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,\
- TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,\
- TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,\
+ ECDHE_RSA_WITH_AES_128_CBC_SHA256,\
+ ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,\
+ ECDHE_RSA_WITH_AES_256_CBC_SHA384,\
+ DHE_DSS_WITH_AES_128_CBC_SHA256,\
+ DHE_DSS_WITH_AES_256_CBC_SHA256,\
+ DHE_RSA_WITH_AES_256_CBC_SHA256,\
+ DHE_RSA_WITH_AES_128_CBC_SHA256,\
+ DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,\
+ DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,\
+ ECDHE_RSA_WITH_AES_128_CBC_SHA,\
+ ECDHE_ECDSA_WITH_AES_128_CBC_SHA,\
+ ECDHE_RSA_WITH_AES_256_CBC_SHA,\
+ ECDHE_ECDSA_WITH_AES_256_CBC_SHA,\
+ DHE_DSS_WITH_AES_128_CBC_SHA,\
+ DHE_RSA_WITH_AES_128_CBC_SHA,\
+ DHE_RSA_WITH_AES_256_CBC_SHA,\
+ DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,\
+ RSA_WITH_CAMELLIA_128_CBC_SHA,\
+ DH_RSA_WITH_AES_128_CBC_SHA256,\
+ ECDH_ECDSA_WITH_AES_128_CBC_SHA256,\
+ ECDH_RSA_WITH_AES_128_CBC_SHA256,\
+ DH_RSA_WITH_AES_256_CBC_SHA256,\
+ ECDH_RSA_WITH_AES_256_CBC_SHA384,\
+ DH_DSS_WITH_AES_128_CBC_SHA256,\
+ ECDH_ECDSA_WITH_AES_256_CBC_SHA384,\
+ DH_DSS_WITH_AES_128_CBC_SHA,\
+ ECDH_ECDSA_WITH_AES_128_CBC_SHA,\
+ DH_DSS_WITH_AES_256_CBC_SHA,\
+ ECDH_ECDSA_WITH_AES_256_CBC_SHA,\
+ DH_DSS_WITH_AES_256_CBC_SHA256,\
+ DH_RSA_WITH_AES_128_CBC_SHA,\
+ ECDH_RSA_WITH_AES_128_CBC_SHA,\
+ DH_RSA_WITH_AES_256_CBC_SHA,\
+ ECDH_RSA_WITH_AES_256_CBC_SHA,\
+ RSA_WITH_AES_128_GCM_SHA256,\
+ RSA_WITH_AES_128_CCM,\
+ RSA_WITH_AES_128_CCM_8,\
+ RSA_WITH_AES_256_GCM_SHA384,\
+ RSA_WITH_AES_256_CCM,\
+ RSA_WITH_AES_256_CCM_8,\
+ RSA_WITH_AES_128_CBC_SHA256,\
+ RSA_WITH_AES_256_CBC_SHA256,\
+ RSA_WITH_AES_128_CBC_SHA,\
+ RSA_WITH_AES_256_CBC_SHA,\
+ RSA_WITH_CAMELLIA_256_CBC_SHA,\
+ RSA_WITH_CAMELLIA_128_CBC_SHA,\
+ DH_DSS_WITH_AES_128_GCM_SHA256,\
+ ECDH_ECDSA_WITH_AES_128_GCM_SHA256,\
+ DH_DSS_WITH_AES_256_GCM_SHA384,\
+ ECDH_ECDSA_WITH_AES_256_GCM_SHA384,\
+ DH_RSA_WITH_AES_128_GCM_SHA256,\
+ ECDH_RSA_WITH_AES_128_GCM_SHA256,\
+ DH_RSA_WITH_AES_256_GCM_SHA384,\
+ ECDH_RSA_WITH_AES_256_GCM_SHA384,\
+ DH_DSS_WITH_3DES_EDE_CBC_SHA,\
+ DH_RSA_WITH_3DES_EDE_CBC_SHA,\
+ DHE_DSS_WITH_3DES_EDE_CBC_SHA,\
+ DHE_RSA_WITH_3DES_EDE_CBC_SHA,\
+ ECDH_RSA_WITH_3DES_EDE_CBC_SHA,\
+ ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,\
+ ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,\
+ ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,\
+ RSA_WITH_3DES_EDE_CBC_SHA
# Unacceptable TLS Ciphers
TLSCiphers.Unacceptable.Mask=_ANON_,_NULL_,_EXPORT,_MD5,_DES,_RC2_,_RC4_,_PSK_
diff --git a/src/main/user-api/java/com/mysql/cj/jdbc/JdbcStatement.java b/src/main/user-api/java/com/mysql/cj/jdbc/JdbcStatement.java
index d80b877ad..ff3ccf89f 100644
--- a/src/main/user-api/java/com/mysql/cj/jdbc/JdbcStatement.java
+++ b/src/main/user-api/java/com/mysql/cj/jdbc/JdbcStatement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2007, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -123,4 +123,8 @@ public interface JdbcStatement extends java.sql.Statement, Query {
void setHoldResultsOpenOverClose(boolean holdResultsOpenOverClose);
Query getQuery();
+
+ void setAttribute(String name, Object value);
+
+ void clearAttributes();
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/CallableStatement.java b/src/main/user-impl/java/com/mysql/cj/jdbc/CallableStatement.java
index 9b4fce5eb..251008992 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/CallableStatement.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/CallableStatement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -58,6 +58,7 @@
import com.mysql.cj.Messages;
import com.mysql.cj.MysqlType;
+import com.mysql.cj.ParseInfo;
import com.mysql.cj.PreparedQuery;
import com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm;
import com.mysql.cj.conf.PropertyKey;
@@ -71,6 +72,7 @@
import com.mysql.cj.result.DefaultColumnDefinition;
import com.mysql.cj.result.Field;
import com.mysql.cj.result.Row;
+import com.mysql.cj.util.SearchMode;
import com.mysql.cj.util.StringUtils;
import com.mysql.cj.util.Util;
@@ -530,7 +532,7 @@ private void generateParameterMap() throws SQLException {
int parenOpenPos = q.getOriginalSql().indexOf('(', startPos + 4);
if (parenOpenPos != -1) {
- int parenClosePos = StringUtils.indexOfIgnoreCase(parenOpenPos, q.getOriginalSql(), ")", "'", "'", StringUtils.SEARCH_MODE__ALL);
+ int parenClosePos = StringUtils.indexOfIgnoreCase(parenOpenPos, q.getOriginalSql(), ")", "'", "'", SearchMode.__FULL);
if (parenClosePos != -1) {
List> parsedParameters = StringUtils.split(q.getOriginalSql().substring(parenOpenPos + 1, parenClosePos), ",", "'\"", "'\"",
@@ -705,8 +707,8 @@ public void clearParameters() throws SQLException {
*/
private void fakeParameterTypes(boolean isReallyProcedure) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
- String encoding = this.connection.getSession().getServerSession().getCharacterSetMetadata();
- int collationIndex = this.connection.getSession().getServerSession().getMetadataCollationIndex();
+ String encoding = this.connection.getSession().getServerSession().getCharsetSettings().getMetadataEncoding();
+ int collationIndex = this.connection.getSession().getServerSession().getCharsetSettings().getMetadataCollationIndex();
Field[] fields = new Field[13];
fields[0] = new Field("", "PROCEDURE_CAT", collationIndex, encoding, MysqlType.CHAR, 0);
@@ -900,7 +902,8 @@ public int executeUpdate() throws SQLException {
}
private String extractProcedureName() throws SQLException {
- String sanitizedSql = StringUtils.stripComments(((PreparedQuery>) this.query).getOriginalSql(), "`\"'", "`\"'", true, false, true, true);
+ String sanitizedSql = StringUtils.stripCommentsAndHints(((PreparedQuery>) this.query).getOriginalSql(), "`'\"", "`'\"",
+ !this.session.getServerSession().isNoBackslashEscapesSet());
// TODO: Do this with less memory allocation
int endCallIndex = StringUtils.indexOfIgnoreCase(sanitizedSql, "CALL ");
@@ -2330,7 +2333,20 @@ private boolean checkReadOnlyProcedure() throws SQLException {
@Override
protected boolean checkReadOnlySafeStatement() throws SQLException {
- return (super.checkReadOnlySafeStatement() || this.checkReadOnlyProcedure());
+ if (ParseInfo.isReadOnlySafeQuery(((PreparedQuery>) this.query).getOriginalSql(), this.session.getServerSession().isNoBackslashEscapesSet())) {
+ String sql = ((PreparedQuery>) this.query).getOriginalSql();
+ int statementKeywordPos = ParseInfo.indexOfStatementKeyword(sql, this.session.getServerSession().isNoBackslashEscapesSet());
+ if (StringUtils.startsWithIgnoreCaseAndWs(sql, "CALL", statementKeywordPos)
+ || StringUtils.startsWithIgnoreCaseAndWs(sql, "SELECT", statementKeywordPos)) {
+ // "CALL" and "SELECT" are read-only safe but the routine they call may not be.
+ if (!this.connection.isReadOnly()) { // Only proceed with checking the routine body if really needed.
+ return true;
+ }
+ return checkReadOnlyProcedure();
+ }
+ return true;
+ }
+ return !this.connection.isReadOnly();
}
@Override
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ClientPreparedStatement.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ClientPreparedStatement.java
index 4127b0495..c2fa0832a 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ClientPreparedStatement.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ClientPreparedStatement.java
@@ -63,6 +63,7 @@
import com.mysql.cj.PreparedQuery;
import com.mysql.cj.Query;
import com.mysql.cj.QueryBindings;
+import com.mysql.cj.QueryReturnType;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.exceptions.CJException;
import com.mysql.cj.exceptions.FeatureNotAvailableException;
@@ -80,7 +81,6 @@
import com.mysql.cj.protocol.Message;
import com.mysql.cj.protocol.a.NativePacketPayload;
import com.mysql.cj.result.Field;
-import com.mysql.cj.util.StringUtils;
import com.mysql.cj.util.Util;
/**
@@ -304,7 +304,8 @@ public void clearParameters() throws SQLException {
*/
protected boolean checkReadOnlySafeStatement() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
- return ((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S' || !this.connection.isReadOnly();
+ return ParseInfo.isReadOnlySafeQuery(((PreparedQuery>) this.query).getOriginalSql(), this.session.getServerSession().isNoBackslashEscapesSet())
+ || !this.connection.isReadOnly();
}
}
@@ -365,10 +366,9 @@ public boolean execute() throws SQLException {
//
// Only apply max_rows to selects
//
- locallyScopedConn.setSessionMaxRows(((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S' ? this.maxRows : -1);
+ locallyScopedConn.setSessionMaxRows(getParseInfo().getFirstStmtChar() == 'S' ? this.maxRows : -1);
- rs = executeInternal(this.maxRows, sendPacket, createStreamingResultSet(),
- (((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S'), cachedMetadata, false);
+ rs = executeInternal(this.maxRows, sendPacket, createStreamingResultSet(), (getParseInfo().getFirstStmtChar() == 'S'), cachedMetadata, false);
if (cachedMetadata != null) {
locallyScopedConn.initializeResultsMetadataFromCache(((PreparedQuery>) this.query).getOriginalSql(), cachedMetadata, rs);
@@ -379,7 +379,7 @@ public boolean execute() throws SQLException {
}
if (this.retrieveGeneratedKeys) {
- rs.setFirstCharOfQuery(((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar());
+ rs.setFirstCharOfQuery(getParseInfo().getFirstStmtChar());
}
if (oldDb != null) {
@@ -422,7 +422,7 @@ protected long[] executeBatchInternal() throws SQLException {
if (!this.batchHasPlainStatements && this.rewriteBatchedStatements.getValue()) {
- if (((PreparedQuery>) this.query).getParseInfo().canRewriteAsMultiValueInsertAtSqlLevel()) {
+ if (getParseInfo().canRewriteAsMultiValueInsertAtSqlLevel()) {
return executeBatchedInserts(batchTimeout);
}
@@ -486,7 +486,7 @@ protected long[] executePreparedBatchAsMultiStatement(int batchTimeout) throws S
int numberToExecuteAsMultiValue = 0;
int batchCounter = 0;
int updateCountCounter = 0;
- long[] updateCounts = new long[numBatchedArgs * ((PreparedQuery>) this.query).getParseInfo().numberOfQueries];
+ long[] updateCounts = new long[numBatchedArgs * getParseInfo().getNumberOfQueries()];
SQLException sqlEx = null;
try {
@@ -653,7 +653,7 @@ private String generateMultiStatementForBatch(int numBatches) throws SQLExceptio
*/
protected long[] executeBatchedInserts(int batchTimeout) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
- String valuesClause = ((PreparedQuery>) this.query).getParseInfo().getValuesClause();
+ String valuesClause = getParseInfo().getValuesClause();
JdbcConnection locallyScopedConn = this.connection;
@@ -959,7 +959,13 @@ public java.sql.ResultSet executeQuery() throws SQLException {
JdbcConnection locallyScopedConn = this.connection;
- checkForDml(((PreparedQuery>) this.query).getOriginalSql(), ((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar());
+ if (!this.doPingInstead) {
+ QueryReturnType queryReturnType = getParseInfo().getQueryReturnType();
+ if (queryReturnType != QueryReturnType.PRODUCES_RESULT_SET && queryReturnType != QueryReturnType.MAY_PRODUCE_RESULT_SET) {
+ throw SQLError.createSQLException(Messages.getString("Statement.57"), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT,
+ getExceptionInterceptor());
+ }
+ }
this.batchedGeneratedKeys = null;
@@ -1065,7 +1071,7 @@ protected long executeUpdateInternal(QueryBindings> bindings, boolean isReally
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
}
- if ((((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar() == 'S') && isSelectQuery()) {
+ if (!isNonResultSetProducingQuery()) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.37"), "01S03", this.exceptionInterceptor);
}
@@ -1092,7 +1098,7 @@ protected long executeUpdateInternal(QueryBindings> bindings, boolean isReally
rs = executeInternal(-1, sendPacket, false, false, null, isReallyBatch);
if (this.retrieveGeneratedKeys) {
- rs.setFirstCharOfQuery(((PreparedQuery>) this.query).getParseInfo().getFirstStmtChar());
+ rs.setFirstCharOfQuery(getParseInfo().getFirstStmtChar());
}
if (oldDb != null) {
@@ -1116,7 +1122,7 @@ protected long executeUpdateInternal(QueryBindings> bindings, boolean isReally
}
protected boolean containsOnDuplicateKeyUpdateInSQL() {
- return ((PreparedQuery>) this.query).getParseInfo().containsOnDuplicateKeyUpdateInSQL();
+ return getParseInfo().containsOnDuplicateKeyUpdateInSQL();
}
/**
@@ -1133,10 +1139,12 @@ protected boolean containsOnDuplicateKeyUpdateInSQL() {
protected ClientPreparedStatement prepareBatchedInsertSQL(JdbcConnection localConn, int numBatches) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
ClientPreparedStatement pstmt = new ClientPreparedStatement(localConn, "Rewritten batch of: " + ((PreparedQuery>) this.query).getOriginalSql(),
- this.getCurrentDatabase(), ((PreparedQuery>) this.query).getParseInfo().getParseInfoForBatch(numBatches));
+ this.getCurrentDatabase(), getParseInfo().getParseInfoForBatch(numBatches));
pstmt.setRetrieveGeneratedKeys(this.retrieveGeneratedKeys);
pstmt.rewrittenBatchSize = numBatches;
+ getQueryAttributesBindings().runThroughAll(a -> ((JdbcStatement) pstmt).setAttribute(a.getName(), a.getValue()));
+
return pstmt;
}
}
@@ -1172,7 +1180,7 @@ public java.sql.ResultSetMetaData getMetaData() throws SQLException {
// CALL's are trapped further up and you end up with a CallableStatement anyway.
//
- if (!isSelectQuery()) {
+ if (!isResultSetProducingQuery()) {
return null;
}
@@ -1182,7 +1190,7 @@ public java.sql.ResultSetMetaData getMetaData() throws SQLException {
if (this.pstmtResultMetaData == null) {
try {
mdStmt = new ClientPreparedStatement(this.connection, ((PreparedQuery>) this.query).getOriginalSql(), this.getCurrentDatabase(),
- ((PreparedQuery>) this.query).getParseInfo());
+ getParseInfo());
mdStmt.setMaxRows(1);
@@ -1236,11 +1244,26 @@ public java.sql.ResultSetMetaData getMetaData() throws SQLException {
}
}
- protected boolean isSelectQuery() throws SQLException {
- synchronized (checkClosed().getConnectionMutex()) {
- return StringUtils.startsWithIgnoreCaseAndWs(
- StringUtils.stripComments(((PreparedQuery>) this.query).getOriginalSql(), "'\"", "'\"", true, false, true, true), "SELECT");
- }
+ /**
+ * Checks if the given SQL query is a result set producing query.
+ *
+ * @return
+ * true
if the query produces a result set, false
otherwise.
+ */
+ protected boolean isResultSetProducingQuery() {
+ QueryReturnType queryReturnType = getParseInfo().getQueryReturnType();
+ return queryReturnType == QueryReturnType.PRODUCES_RESULT_SET || queryReturnType == QueryReturnType.MAY_PRODUCE_RESULT_SET;
+ }
+
+ /**
+ * Checks if the given SQL query does not return a result set.
+ *
+ * @return
+ * true
if the query does not produce a result set, false
otherwise.
+ */
+ private boolean isNonResultSetProducingQuery() {
+ QueryReturnType queryReturnType = getParseInfo().getQueryReturnType();
+ return queryReturnType == QueryReturnType.DOES_NOT_PRODUCE_RESULT_SET || queryReturnType == QueryReturnType.MAY_PRODUCE_RESULT_SET;
}
@Override
@@ -1268,10 +1291,10 @@ public ParseInfo getParseInfo() {
private void initializeFromParseInfo() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
- int parameterCount = ((PreparedQuery) this.query).getParseInfo().getStaticSql().length - 1;
+ int parameterCount = getParseInfo().getStaticSql().length - 1;
((PreparedQuery>) this.query).setParameterCount(parameterCount);
((PreparedQuery) this.query).setQueryBindings(new ClientPreparedQueryBindings(parameterCount, this.session));
- ((ClientPreparedQuery) this.query).getQueryBindings().setLoadDataQuery(((PreparedQuery>) this.query).getParseInfo().isFoundLoadData());
+ ((ClientPreparedQuery) this.query).getQueryBindings().setLoadDataQuery(getParseInfo().isLoadData());
clearParameters();
}
@@ -1323,7 +1346,7 @@ public String getPreparedSql() {
}
try {
- return ((PreparedQuery>) this.query).getParseInfo().getSqlForBatch();
+ return getParseInfo().getSqlForBatch();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionImpl.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionImpl.java
index b8aa34781..2a149e0a4 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionImpl.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionImpl.java
@@ -70,6 +70,7 @@
import com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.conf.RuntimeProperty;
+import com.mysql.cj.exceptions.CJCommunicationsException;
import com.mysql.cj.exceptions.CJException;
import com.mysql.cj.exceptions.ExceptionFactory;
import com.mysql.cj.exceptions.ExceptionInterceptor;
@@ -89,6 +90,7 @@
import com.mysql.cj.jdbc.result.UpdatableResultSet;
import com.mysql.cj.log.ProfilerEvent;
import com.mysql.cj.log.StandardLogger;
+import com.mysql.cj.protocol.ServerSessionStateController;
import com.mysql.cj.protocol.SocksProxySocketFactory;
import com.mysql.cj.util.LRUCache;
import com.mysql.cj.util.StringUtils;
@@ -201,12 +203,6 @@ public int hashCode() {
}
}
- /**
- * The mapping between MySQL charset names and Java charset names.
- * Initialized by loadCharacterSetMapping()
- */
- public static Map, ?> charsetMap;
-
/** Default logger class name */
protected static final String DEFAULT_LOGGER_CLASS = StandardLogger.class.getName();
@@ -560,7 +556,7 @@ public void changeUser(String userName, String newPassword) throws SQLException
this.user = userName;
this.password = newPassword;
- this.session.configureClientCharacterSet(true);
+ this.session.getServerSession().getCharsetSettings().configurePostHandshake(true);
this.session.setSessionVariables();
@@ -1133,7 +1129,7 @@ public String getCatalog() throws SQLException {
@Override
public String getCharacterSetMetadata() {
synchronized (getConnectionMutex()) {
- return this.session.getServerSession().getCharacterSetMetadata();
+ return this.session.getServerSession().getCharsetSettings().getMetadataEncoding();
}
}
@@ -1176,8 +1172,8 @@ private java.sql.DatabaseMetaData getMetaData(boolean checkClosed, boolean check
this.nullStatementResultSetFactory);
if (getSession() != null && getSession().getProtocol() != null) {
- dbmeta.setMetadataEncoding(getSession().getServerSession().getCharacterSetMetadata());
- dbmeta.setMetadataCollationIndex(getSession().getServerSession().getMetadataCollationIndex());
+ dbmeta.setMetadataEncoding(getSession().getServerSession().getCharsetSettings().getMetadataEncoding());
+ dbmeta.setMetadataCollationIndex(getSession().getServerSession().getCharsetSettings().getMetadataCollationIndex());
}
return dbmeta;
@@ -1304,8 +1300,6 @@ private void initializePropsFromServer() throws SQLException {
this.autoIncrementIncrement = this.session.getServerSession().getServerVariable("auto_increment_increment", 1);
- this.session.buildCollationMapping();
-
try {
LicenseConfiguration.checkLicenseType(this.session.getServerSession().getServerVariables());
} catch (CJException e) {
@@ -1316,20 +1310,11 @@ private void initializePropsFromServer() throws SQLException {
checkTransactionIsolationLevel();
- this.session.checkForCharsetMismatch();
-
- this.session.configureClientCharacterSet(false);
-
handleAutoCommitDefaults();
- //
- // We need to figure out what character set metadata and error messages will be returned in, and then map them to Java encoding names
- //
- // We've already set it, and it might be different than what was originally on the server, which is why we use the "special" key to retrieve it
- this.session.getServerSession().configureCharacterSets();
-
- ((com.mysql.cj.jdbc.DatabaseMetaData) this.dbmd).setMetadataEncoding(getSession().getServerSession().getCharacterSetMetadata());
- ((com.mysql.cj.jdbc.DatabaseMetaData) this.dbmd).setMetadataCollationIndex(getSession().getServerSession().getMetadataCollationIndex());
+ ((com.mysql.cj.jdbc.DatabaseMetaData) this.dbmd).setMetadataEncoding(this.session.getServerSession().getCharsetSettings().getMetadataEncoding());
+ ((com.mysql.cj.jdbc.DatabaseMetaData) this.dbmd)
+ .setMetadataCollationIndex(this.session.getServerSession().getCharsetSettings().getMetadataCollationIndex());
//
// Server can do this more efficiently for us
@@ -2033,10 +2018,10 @@ void forEach(ConnectionLifecycleInterceptor each) throws SQLException {
this.autoReconnect.setValue(true);
}
+ boolean isAutocommit = this.session.getServerSession().isAutocommit();
try {
boolean needsSetOnServer = true;
-
- if (this.useLocalSessionState.getValue() && this.session.getServerSession().isAutoCommit() == autoCommitFlag) {
+ if (this.useLocalSessionState.getValue() && isAutocommit == autoCommitFlag) {
needsSetOnServer = false;
} else if (!this.autoReconnect.getValue()) {
needsSetOnServer = getSession().isSetNeededForAutoCommitMode(autoCommitFlag);
@@ -2051,6 +2036,13 @@ void forEach(ConnectionLifecycleInterceptor each) throws SQLException {
this.session.execSQL(null, autoCommitFlag ? "SET autocommit=1" : "SET autocommit=0", -1, null, false, this.nullStatementResultSetFactory,
null, false);
}
+ } catch (CJCommunicationsException e) {
+ throw e;
+ } catch (CJException e) {
+ // Reset to current autocommit value in case of an exception different than a communication exception occurs.
+ this.session.getServerSession().setAutoCommit(isAutocommit);
+ // Update the stacktrace.
+ throw SQLError.createSQLException(e.getMessage(), e.getSQLState(), e.getVendorCode(), e.isTransient(), e, getExceptionInterceptor());
} finally {
if (this.autoReconnectForPools.getValue()) {
this.autoReconnect.setValue(false);
@@ -2700,4 +2692,9 @@ public void handleCleanup(Throwable whyCleanedUp) {
cleanup(whyCleanedUp);
}
+ @Override
+ public ServerSessionStateController getServerSessionStateController() {
+ return this.session.getServerSession().getServerSessionStateController();
+ }
+
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionWrapper.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionWrapper.java
index 367cdb197..4b0202058 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionWrapper.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionWrapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -59,6 +59,7 @@
import com.mysql.cj.jdbc.exceptions.SQLError;
import com.mysql.cj.jdbc.result.CachedResultSetMetaData;
import com.mysql.cj.jdbc.result.ResultSetInternalMethods;
+import com.mysql.cj.protocol.ServerSessionStateController;
/**
* This class serves as a wrapper for the connection object. It is returned to the application server which may wrap it again and then return it to the
@@ -1243,4 +1244,8 @@ public void cleanup(Throwable whyCleanedUp) {
this.mc.cleanup(whyCleanedUp);
}
+ @Override
+ public ServerSessionStateController getServerSessionStateController() {
+ return this.mc.getServerSessionStateController();
+ }
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaData.java b/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaData.java
index 02309a52b..bade0ecfd 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaData.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaData.java
@@ -72,6 +72,7 @@
import com.mysql.cj.result.DefaultColumnDefinition;
import com.mysql.cj.result.Field;
import com.mysql.cj.result.Row;
+import com.mysql.cj.util.SearchMode;
import com.mysql.cj.util.StringUtils;
/**
@@ -1060,13 +1061,14 @@ public List extractForeignKeyForTable(ArrayList rows, java.sql.ResultS
if (indexOfFK != -1) {
int afterFk = indexOfFK + "FOREIGN KEY".length();
- int indexOfRef = StringUtils.indexOfIgnoreCase(afterFk, line, "REFERENCES", this.quotedId, this.quotedId, StringUtils.SEARCH_MODE__ALL);
+ int indexOfRef = StringUtils.indexOfIgnoreCase(afterFk, line, "REFERENCES", this.quotedId, this.quotedId,
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (indexOfRef != -1) {
int indexOfParenOpen = line.indexOf('(', afterFk);
int indexOfParenClose = StringUtils.indexOfIgnoreCase(indexOfParenOpen, line, ")", this.quotedId, this.quotedId,
- StringUtils.SEARCH_MODE__ALL);
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (indexOfParenOpen == -1 || indexOfParenClose == -1) {
// throw SQLError.createSQLException();
@@ -1077,20 +1079,20 @@ public List extractForeignKeyForTable(ArrayList rows, java.sql.ResultS
int afterRef = indexOfRef + "REFERENCES".length();
int referencedColumnBegin = StringUtils.indexOfIgnoreCase(afterRef, line, "(", this.quotedId, this.quotedId,
- StringUtils.SEARCH_MODE__ALL);
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (referencedColumnBegin != -1) {
referencedTableName = line.substring(afterRef, referencedColumnBegin);
int referencedColumnEnd = StringUtils.indexOfIgnoreCase(referencedColumnBegin + 1, line, ")", this.quotedId, this.quotedId,
- StringUtils.SEARCH_MODE__ALL);
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (referencedColumnEnd != -1) {
referencedColumnName = line.substring(referencedColumnBegin + 1, referencedColumnEnd);
}
int indexOfDbSep = StringUtils.indexOfIgnoreCase(0, referencedTableName, ".", this.quotedId, this.quotedId,
- StringUtils.SEARCH_MODE__ALL);
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (indexOfDbSep != -1) {
referencedDbName = referencedTableName.substring(0, indexOfDbSep);
@@ -1435,7 +1437,7 @@ private void getCallStmtParameterTypes(String db, String quotedProcName, Procedu
int dotIndex = " ".equals(this.quotedId) ? quotedProcName.indexOf(".")
: StringUtils.indexOfIgnoreCase(0, quotedProcName, ".", this.quotedId, this.quotedId,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
String dbName = null;
@@ -1495,10 +1497,11 @@ private void getCallStmtParameterTypes(String db, String quotedProcName, Procedu
if (procedureDef != null && procedureDef.length() != 0) {
// sanitize/normalize by stripping out comments
- procedureDef = StringUtils.stripComments(procedureDef, identifierAndStringMarkers, identifierAndStringMarkers, true, false, true, true);
+ procedureDef = StringUtils.stripCommentsAndHints(procedureDef, identifierAndStringMarkers, identifierAndStringMarkers,
+ !this.session.getServerSession().isNoBackslashEscapesSet());
int openParenIndex = StringUtils.indexOfIgnoreCase(0, procedureDef, "(", this.quotedId, this.quotedId,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__FULL);
int endOfParamDeclarationIndex = 0;
endOfParamDeclarationIndex = endPositionOfParameterDeclaration(openParenIndex, procedureDef, this.quotedId);
@@ -1508,7 +1511,7 @@ private void getCallStmtParameterTypes(String db, String quotedProcName, Procedu
// Grab the return column since it needs
// to go first in the output result set
int returnsIndex = StringUtils.indexOfIgnoreCase(0, procedureDef, " RETURNS ", this.quotedId, this.quotedId,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__FULL);
int endReturnsDef = findEndOfReturnsClause(procedureDef, returnsIndex);
@@ -1691,11 +1694,11 @@ private int endPositionOfParameterDeclaration(int beginIndex, String procedureDe
while (parenDepth > 0 && currentPos < procedureDef.length()) {
int closedParenIndex = StringUtils.indexOfIgnoreCase(currentPos, procedureDef, ")", quoteChar, quoteChar,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (closedParenIndex != -1) {
int nextOpenParenIndex = StringUtils.indexOfIgnoreCase(currentPos, procedureDef, "(", quoteChar, quoteChar,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (nextOpenParenIndex != -1 && nextOpenParenIndex < closedParenIndex) {
parenDepth++;
@@ -1743,7 +1746,7 @@ private int findEndOfReturnsClause(String procedureDefn, int positionOfReturnKey
for (int i = 0; i < tokens.length; i++) {
int nextEndOfReturn = StringUtils.indexOfIgnoreCase(startLookingAt, procedureDefn, tokens[i], openingMarkers, closingMarkers,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (nextEndOfReturn != -1) {
if (endOfReturn == -1 || (nextEndOfReturn < endOfReturn)) {
@@ -1758,7 +1761,7 @@ private int findEndOfReturnsClause(String procedureDefn, int positionOfReturnKey
// Label?
endOfReturn = StringUtils.indexOfIgnoreCase(startLookingAt, procedureDefn, ":", openingMarkers, closingMarkers,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (endOfReturn != -1) {
// seek back until whitespace
@@ -3167,7 +3170,7 @@ protected java.sql.ResultSet getProcedureOrFunctionColumns(Field[] fields, Strin
//Continuing from above (database_name.sp_name)
if (!" ".equals(this.quotedId)) {
idx = StringUtils.indexOfIgnoreCase(0, procName, ".", this.quotedId, this.quotedId,
- this.session.getServerSession().isNoBackslashEscapesSet() ? StringUtils.SEARCH_MODE__MRK_COM_WS : StringUtils.SEARCH_MODE__ALL);
+ this.session.getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
} else {
idx = procName.indexOf(".");
}
@@ -4331,7 +4334,8 @@ protected LocalAndReferencedColumns parseTableStatusIntoLocalAndReferencedColumn
String columnsDelimitter = ","; // what version did this change in?
- int indexOfOpenParenLocalColumns = StringUtils.indexOfIgnoreCase(0, keysComment, "(", this.quotedId, this.quotedId, StringUtils.SEARCH_MODE__ALL);
+ int indexOfOpenParenLocalColumns = StringUtils.indexOfIgnoreCase(0, keysComment, "(", this.quotedId, this.quotedId,
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (indexOfOpenParenLocalColumns == -1) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.14"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
@@ -4343,7 +4347,7 @@ protected LocalAndReferencedColumns parseTableStatusIntoLocalAndReferencedColumn
String keysCommentTrimmed = keysComment.trim();
int indexOfCloseParenLocalColumns = StringUtils.indexOfIgnoreCase(0, keysCommentTrimmed, ")", this.quotedId, this.quotedId,
- StringUtils.SEARCH_MODE__ALL);
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (indexOfCloseParenLocalColumns == -1) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.15"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
@@ -4351,14 +4355,14 @@ protected LocalAndReferencedColumns parseTableStatusIntoLocalAndReferencedColumn
String localColumnNamesString = keysCommentTrimmed.substring(1, indexOfCloseParenLocalColumns);
- int indexOfRefer = StringUtils.indexOfIgnoreCase(0, keysCommentTrimmed, "REFER ", this.quotedId, this.quotedId, StringUtils.SEARCH_MODE__ALL);
+ int indexOfRefer = StringUtils.indexOfIgnoreCase(0, keysCommentTrimmed, "REFER ", this.quotedId, this.quotedId, SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (indexOfRefer == -1) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.16"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
int indexOfOpenParenReferCol = StringUtils.indexOfIgnoreCase(indexOfRefer, keysCommentTrimmed, "(", this.quotedId, this.quotedId,
- StringUtils.SEARCH_MODE__MRK_COM_WS);
+ SearchMode.__MRK_COM_MYM_HNT_WS);
if (indexOfOpenParenReferCol == -1) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.17"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
@@ -4366,7 +4370,7 @@ protected LocalAndReferencedColumns parseTableStatusIntoLocalAndReferencedColumn
String referDbTableString = keysCommentTrimmed.substring(indexOfRefer + "REFER ".length(), indexOfOpenParenReferCol);
- int indexOfSlash = StringUtils.indexOfIgnoreCase(0, referDbTableString, "/", this.quotedId, this.quotedId, StringUtils.SEARCH_MODE__MRK_COM_WS);
+ int indexOfSlash = StringUtils.indexOfIgnoreCase(0, referDbTableString, "/", this.quotedId, this.quotedId, SearchMode.__MRK_COM_MYM_HNT_WS);
if (indexOfSlash == -1) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.18"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
@@ -4376,7 +4380,7 @@ protected LocalAndReferencedColumns parseTableStatusIntoLocalAndReferencedColumn
String referTable = StringUtils.unQuoteIdentifier(referDbTableString.substring(indexOfSlash + 1).trim(), this.quotedId);
int indexOfCloseParenRefer = StringUtils.indexOfIgnoreCase(indexOfOpenParenReferCol, keysCommentTrimmed, ")", this.quotedId, this.quotedId,
- StringUtils.SEARCH_MODE__ALL);
+ SearchMode.__BSE_MRK_COM_MYM_HNT_WS);
if (indexOfCloseParenRefer == -1) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.19"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java b/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java
index 4334444a8..8f1d3e19f 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java
@@ -299,9 +299,9 @@ public java.sql.ResultSet getCrossReference(String primaryCatalog, String primar
primaryDb = this.pedantic ? primaryDb : StringUtils.unQuoteIdentifier(primaryDb, this.quotedId);
foreignDb = this.pedantic ? foreignDb : StringUtils.unQuoteIdentifier(foreignDb, this.quotedId);
- StringBuilder sqlBuf = new StringBuilder(
- this.databaseTerm.getValue() == DatabaseTerm.SCHEMA ? "SELECT A.CONSTRAINT_CATALOG AS PKTABLE_CAT, A.REFERENCED_TABLE_SCHEMA AS PKTABLE_SCHEM,"
- : "SELECT A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,NULL AS PKTABLE_SCHEM,");
+ StringBuilder sqlBuf = new StringBuilder(this.databaseTerm.getValue() == DatabaseTerm.SCHEMA
+ ? "SELECT DISTINCT A.CONSTRAINT_CATALOG AS PKTABLE_CAT, A.REFERENCED_TABLE_SCHEMA AS PKTABLE_SCHEM,"
+ : "SELECT DISTINCT A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,NULL AS PKTABLE_SCHEM,");
sqlBuf.append(" A.REFERENCED_TABLE_NAME AS PKTABLE_NAME, A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,");
sqlBuf.append(this.databaseTerm.getValue() == DatabaseTerm.SCHEMA ? " A.TABLE_CATALOG AS FKTABLE_CAT, A.TABLE_SCHEMA AS FKTABLE_SCHEM,"
: " A.TABLE_SCHEMA AS FKTABLE_CAT, NULL AS FKTABLE_SCHEM,");
@@ -309,13 +309,14 @@ public java.sql.ResultSet getCrossReference(String primaryCatalog, String primar
sqlBuf.append(generateUpdateRuleClause());
sqlBuf.append(" AS UPDATE_RULE,");
sqlBuf.append(generateDeleteRuleClause());
- sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME,");
- sqlBuf.append(" (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = A.REFERENCED_TABLE_SCHEMA");
- sqlBuf.append(" AND TABLE_NAME = A.REFERENCED_TABLE_NAME AND CONSTRAINT_TYPE IN ('UNIQUE','PRIMARY KEY') LIMIT 1) AS PK_NAME, ");
+ sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME, TC.CONSTRAINT_NAME AS PK_NAME,");
sqlBuf.append(importedKeyNotDeferrable);
sqlBuf.append(" AS DEFERRABILITY FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE A");
sqlBuf.append(" JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS B USING (TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_NAME) ");
sqlBuf.append(generateOptionalRefContraintsJoin());
+ sqlBuf.append(" LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC ON (A.REFERENCED_TABLE_SCHEMA = TC.TABLE_SCHEMA");
+ sqlBuf.append(" AND A.REFERENCED_TABLE_NAME = TC.TABLE_NAME");
+ sqlBuf.append(" AND TC.CONSTRAINT_TYPE IN ('UNIQUE', 'PRIMARY KEY'))");
sqlBuf.append("WHERE B.CONSTRAINT_TYPE = 'FOREIGN KEY'");
if (primaryDb != null) {
sqlBuf.append(" AND A.REFERENCED_TABLE_SCHEMA=?");
@@ -325,7 +326,7 @@ public java.sql.ResultSet getCrossReference(String primaryCatalog, String primar
sqlBuf.append(" AND A.TABLE_SCHEMA = ?");
}
sqlBuf.append(" AND A.TABLE_NAME=?");
- sqlBuf.append(" ORDER BY A.TABLE_SCHEMA, A.TABLE_NAME, A.ORDINAL_POSITION");
+ sqlBuf.append(" ORDER BY FKTABLE_NAME, FKTABLE_NAME, KEY_SEQ");
java.sql.PreparedStatement pStmt = null;
@@ -363,9 +364,9 @@ public java.sql.ResultSet getExportedKeys(String catalog, String schema, String
db = this.pedantic ? db : StringUtils.unQuoteIdentifier(db, this.quotedId);
- StringBuilder sqlBuf = new StringBuilder(
- this.databaseTerm.getValue() == DatabaseTerm.SCHEMA ? "SELECT A.CONSTRAINT_CATALOG AS PKTABLE_CAT, A.REFERENCED_TABLE_SCHEMA AS PKTABLE_SCHEM,"
- : "SELECT A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,NULL AS PKTABLE_SCHEM,");
+ StringBuilder sqlBuf = new StringBuilder(this.databaseTerm.getValue() == DatabaseTerm.SCHEMA
+ ? "SELECT DISTINCT A.CONSTRAINT_CATALOG AS PKTABLE_CAT, A.REFERENCED_TABLE_SCHEMA AS PKTABLE_SCHEM,"
+ : "SELECT DISTINCT A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,NULL AS PKTABLE_SCHEM,");
sqlBuf.append(" A.REFERENCED_TABLE_NAME AS PKTABLE_NAME, A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,");
sqlBuf.append(this.databaseTerm.getValue() == DatabaseTerm.SCHEMA ? " A.TABLE_CATALOG AS FKTABLE_CAT, A.TABLE_SCHEMA AS FKTABLE_SCHEM,"
: " A.TABLE_SCHEMA AS FKTABLE_CAT, NULL AS FKTABLE_SCHEM,");
@@ -373,19 +374,20 @@ public java.sql.ResultSet getExportedKeys(String catalog, String schema, String
sqlBuf.append(generateUpdateRuleClause());
sqlBuf.append(" AS UPDATE_RULE,");
sqlBuf.append(generateDeleteRuleClause());
- sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME, (SELECT CONSTRAINT_NAME FROM");
- sqlBuf.append(" INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = A.REFERENCED_TABLE_SCHEMA AND");
- sqlBuf.append(" TABLE_NAME = A.REFERENCED_TABLE_NAME AND CONSTRAINT_TYPE IN ('UNIQUE','PRIMARY KEY') LIMIT 1) AS PK_NAME,");
+ sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME, TC.CONSTRAINT_NAME AS PK_NAME,");
sqlBuf.append(importedKeyNotDeferrable);
sqlBuf.append(" AS DEFERRABILITY FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE A");
sqlBuf.append(" JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS B USING (TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_NAME) ");
sqlBuf.append(generateOptionalRefContraintsJoin());
+ sqlBuf.append(" LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC ON (A.REFERENCED_TABLE_SCHEMA = TC.TABLE_SCHEMA");
+ sqlBuf.append(" AND A.REFERENCED_TABLE_NAME = TC.TABLE_NAME");
+ sqlBuf.append(" AND TC.CONSTRAINT_TYPE IN ('UNIQUE', 'PRIMARY KEY'))");
sqlBuf.append(" WHERE B.CONSTRAINT_TYPE = 'FOREIGN KEY'");
if (db != null) {
sqlBuf.append(" AND A.REFERENCED_TABLE_SCHEMA = ?");
}
sqlBuf.append(" AND A.REFERENCED_TABLE_NAME=?");
- sqlBuf.append(" ORDER BY A.TABLE_SCHEMA, A.TABLE_NAME, A.ORDINAL_POSITION");
+ sqlBuf.append(" ORDER BY FKTABLE_NAME, FKTABLE_NAME, KEY_SEQ");
java.sql.PreparedStatement pStmt = null;
@@ -441,9 +443,9 @@ public java.sql.ResultSet getImportedKeys(String catalog, String schema, String
db = this.pedantic ? db : StringUtils.unQuoteIdentifier(db, this.quotedId);
- StringBuilder sqlBuf = new StringBuilder(
- this.databaseTerm.getValue() == DatabaseTerm.SCHEMA ? "SELECT A.CONSTRAINT_CATALOG AS PKTABLE_CAT, A.REFERENCED_TABLE_SCHEMA AS PKTABLE_SCHEM,"
- : "SELECT A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,NULL AS PKTABLE_SCHEM,");
+ StringBuilder sqlBuf = new StringBuilder(this.databaseTerm.getValue() == DatabaseTerm.SCHEMA
+ ? "SELECT DISTINCT A.CONSTRAINT_CATALOG AS PKTABLE_CAT, A.REFERENCED_TABLE_SCHEMA AS PKTABLE_SCHEM,"
+ : "SELECT DISTINCT A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,NULL AS PKTABLE_SCHEM,");
sqlBuf.append(" A.REFERENCED_TABLE_NAME AS PKTABLE_NAME, A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,");
sqlBuf.append(this.databaseTerm.getValue() == DatabaseTerm.SCHEMA ? " A.TABLE_CATALOG AS FKTABLE_CAT, A.TABLE_SCHEMA AS FKTABLE_SCHEM,"
: " A.TABLE_SCHEMA AS FKTABLE_CAT, NULL AS FKTABLE_SCHEM,");
@@ -451,9 +453,7 @@ public java.sql.ResultSet getImportedKeys(String catalog, String schema, String
sqlBuf.append(generateUpdateRuleClause());
sqlBuf.append(" AS UPDATE_RULE,");
sqlBuf.append(generateDeleteRuleClause());
- sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME, (SELECT CONSTRAINT_NAME FROM");
- sqlBuf.append(" INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = A.REFERENCED_TABLE_SCHEMA AND");
- sqlBuf.append(" TABLE_NAME = A.REFERENCED_TABLE_NAME AND CONSTRAINT_TYPE IN ('UNIQUE','PRIMARY KEY') LIMIT 1) AS PK_NAME,");
+ sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME, R.UNIQUE_CONSTRAINT_NAME AS PK_NAME,");
sqlBuf.append(importedKeyNotDeferrable);
sqlBuf.append(" AS DEFERRABILITY FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE A");
sqlBuf.append(" JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS B USING (CONSTRAINT_NAME, TABLE_NAME) ");
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/MysqlSQLXML.java b/src/main/user-impl/java/com/mysql/cj/jdbc/MysqlSQLXML.java
index 41da76e99..27d7cd6ab 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/MysqlSQLXML.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/MysqlSQLXML.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -42,6 +42,7 @@
import java.sql.SQLException;
import java.sql.SQLXML;
+import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
@@ -65,7 +66,9 @@
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
import com.mysql.cj.Messages;
import com.mysql.cj.exceptions.ExceptionInterceptor;
@@ -199,56 +202,54 @@ public T getSource(Class clazz) throws SQLException {
if (clazz == null || clazz.equals(SAXSource.class)) {
- InputSource inputSource = null;
-
- if (this.fromResultSet) {
- inputSource = new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml));
- } else {
- inputSource = new InputSource(new StringReader(this.stringRep));
+ try {
+ XMLReader reader = XMLReaderFactory.createXMLReader();
+ // According to https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
+ reader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ setFeature(reader, "http://apache.org/xml/features/disallow-doctype-decl", true);
+ setFeature(reader, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ setFeature(reader, "http://xml.org/sax/features/external-general-entities", false);
+ setFeature(reader, "http://xml.org/sax/features/external-parameter-entities", false);
+
+ return (T) new SAXSource(reader, this.fromResultSet ? new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml))
+ : new InputSource(new StringReader(this.stringRep)));
+ } catch (SAXException ex) {
+ SQLException sqlEx = SQLError.createSQLException(ex.getMessage(), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, ex, this.exceptionInterceptor);
+ throw sqlEx;
}
- return (T) new SAXSource(inputSource);
} else if (clazz.equals(DOMSource.class)) {
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
- DocumentBuilder builder = builderFactory.newDocumentBuilder();
- InputSource inputSource = null;
+ // According to https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
+ setFeature(builderFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ setFeature(builderFactory, "http://apache.org/xml/features/disallow-doctype-decl", true);
+ setFeature(builderFactory, "http://xml.org/sax/features/external-general-entities", false);
+ setFeature(builderFactory, "http://xml.org/sax/features/external-parameter-entities", false);
+ setFeature(builderFactory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ builderFactory.setXIncludeAware(false);
+ builderFactory.setExpandEntityReferences(false);
- if (this.fromResultSet) {
- inputSource = new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml));
- } else {
- inputSource = new InputSource(new StringReader(this.stringRep));
- }
+ builderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
+ DocumentBuilder builder = builderFactory.newDocumentBuilder();
- return (T) new DOMSource(builder.parse(inputSource));
+ return (T) new DOMSource(builder.parse(this.fromResultSet ? new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml))
+ : new InputSource(new StringReader(this.stringRep))));
} catch (Throwable t) {
SQLException sqlEx = SQLError.createSQLException(t.getMessage(), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, t, this.exceptionInterceptor);
throw sqlEx;
}
} else if (clazz.equals(StreamSource.class)) {
- Reader reader = null;
+ return (T) new StreamSource(this.fromResultSet ? this.owningResultSet.getCharacterStream(this.columnIndexOfXml) : new StringReader(this.stringRep));
- if (this.fromResultSet) {
- reader = this.owningResultSet.getCharacterStream(this.columnIndexOfXml);
- } else {
- reader = new StringReader(this.stringRep);
- }
-
- return (T) new StreamSource(reader);
} else if (clazz.equals(StAXSource.class)) {
try {
- Reader reader = null;
-
- if (this.fromResultSet) {
- reader = this.owningResultSet.getCharacterStream(this.columnIndexOfXml);
- } else {
- reader = new StringReader(this.stringRep);
- }
-
- return (T) new StAXSource(this.inputFactory.createXMLStreamReader(reader));
+ return (T) new StAXSource(this.inputFactory.createXMLStreamReader(
+ this.fromResultSet ? this.owningResultSet.getCharacterStream(this.columnIndexOfXml) : new StringReader(this.stringRep)));
} catch (XMLStreamException ex) {
SQLException sqlEx = SQLError.createSQLException(ex.getMessage(), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, ex, this.exceptionInterceptor);
throw sqlEx;
@@ -259,6 +260,18 @@ public T getSource(Class clazz) throws SQLException {
}
}
+ private static void setFeature(Object factory, String name, boolean value) {
+ try {
+ if (factory instanceof DocumentBuilderFactory) {
+ ((DocumentBuilderFactory) factory).setFeature(name, value);
+ } else if (factory instanceof XMLReader) {
+ ((XMLReader) factory).setFeature(name, value);
+ }
+ } catch (Exception ignore) {
+ // no-op
+ }
+ }
+
@Override
public synchronized OutputStream setBinaryStream() throws SQLException {
checkClosed();
@@ -391,7 +404,7 @@ protected String readerToString(Reader reader) throws SQLException {
protected synchronized Reader serializeAsCharacterStream() throws SQLException {
checkClosed();
- if (this.workingWithResult) {
+ if (this.workingWithResult || this.owningResultSet == null) {
// figure out what kind of result
if (this.stringRep != null) {
return new StringReader(this.stringRep);
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ParameterBindingsImpl.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ParameterBindingsImpl.java
index 489c8a625..b601339c0 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ParameterBindingsImpl.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ParameterBindingsImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2019, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -107,7 +107,7 @@ public class ParameterBindingsImpl implements ParameterBindings {
break;
default:
try {
- charsetIndex = CharsetMapping.getCollationIndexForJavaEncoding(
+ charsetIndex = session.getServerSession().getCharsetSettings().getCollationIndexForJavaEncoding(
this.propertySet.getStringProperty(PropertyKey.characterEncoding).getValue(), session.getServerSession().getServerVersion());
} catch (RuntimeException ex) {
throw SQLError.createSQLException(ex.toString(), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, ex, null);
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ServerPreparedStatement.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ServerPreparedStatement.java
index f1d64fac0..de2e09652 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ServerPreparedStatement.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ServerPreparedStatement.java
@@ -34,7 +34,6 @@
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
-import java.sql.Date;
import java.sql.ParameterMetaData;
import java.sql.SQLException;
import java.sql.Time;
@@ -272,6 +271,7 @@ public void close() throws SQLException {
if (this.isCacheable && isPoolable()) {
clearParameters();
+ clearAttributes();
this.isClosed = true;
@@ -719,10 +719,21 @@ protected int setOneBatchedParameterSet(java.sql.PreparedStatement batchedStatem
if (paramArg[j].isStream()) {
Object value = paramArg[j].value;
- if (value instanceof InputStream) {
+ if (value instanceof byte[]) {
+ batchedStatement.setBytes(batchedParamIndex++, (byte[]) value);
+ } else if (value instanceof InputStream) {
batchedStatement.setBinaryStream(batchedParamIndex++, (InputStream) value, paramArg[j].getStreamLength());
- } else {
+ } else if (value instanceof java.sql.Blob) {
+ try {
+ batchedStatement.setBinaryStream(batchedParamIndex++, ((java.sql.Blob) value).getBinaryStream(), paramArg[j].getStreamLength());
+ } catch (Throwable t) {
+ throw ExceptionFactory.createException(t.getMessage(), this.session.getExceptionInterceptor());
+ }
+ } else if (value instanceof Reader) {
batchedStatement.setCharacterStream(batchedParamIndex++, (Reader) value, paramArg[j].getStreamLength());
+ } else {
+ throw ExceptionFactory.createException(WrongArgumentException.class,
+ Messages.getString("ServerPreparedStatement.18") + value.getClass().getName() + "'", this.session.getExceptionInterceptor());
}
} else {
switch (paramArg[j].bufferType) {
@@ -748,7 +759,7 @@ protected int setOneBatchedParameterSet(java.sql.PreparedStatement batchedStatem
batchedStatement.setTime(batchedParamIndex++, (Time) paramArg[j].value);
break;
case MysqlType.FIELD_TYPE_DATE:
- batchedStatement.setDate(batchedParamIndex++, (Date) paramArg[j].value);
+ batchedStatement.setObject(batchedParamIndex++, paramArg[j].value, MysqlType.DATE);
break;
case MysqlType.FIELD_TYPE_DATETIME:
batchedStatement.setObject(batchedParamIndex++, paramArg[j].value);
@@ -802,6 +813,8 @@ protected ClientPreparedStatement prepareBatchedInsertSQL(JdbcConnection localCo
this.resultSetConcurrency, this.query.getResultType().getIntValue())).unwrap(ClientPreparedStatement.class);
pstmt.setRetrieveGeneratedKeys(this.retrieveGeneratedKeys);
+ getQueryAttributesBindings().runThroughAll(a -> ((JdbcStatement) pstmt).setAttribute(a.getName(), a.getValue()));
+
return pstmt;
} catch (UnsupportedEncodingException e) {
SQLException sqlEx = SQLError.createSQLException(Messages.getString("ServerPreparedStatement.27"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR,
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/StatementImpl.java b/src/main/user-impl/java/com/mysql/cj/jdbc/StatementImpl.java
index d340e2f7c..d841fe1aa 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/StatementImpl.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/StatementImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -43,13 +43,14 @@
import java.util.concurrent.atomic.AtomicBoolean;
import com.mysql.cj.CancelQueryTask;
-import com.mysql.cj.CharsetMapping;
import com.mysql.cj.Messages;
import com.mysql.cj.MysqlType;
import com.mysql.cj.NativeSession;
import com.mysql.cj.ParseInfo;
import com.mysql.cj.PingTarget;
import com.mysql.cj.Query;
+import com.mysql.cj.QueryAttributesBindings;
+import com.mysql.cj.QueryReturnType;
import com.mysql.cj.Session;
import com.mysql.cj.SimpleQuery;
import com.mysql.cj.TransactionEventHandler;
@@ -99,14 +100,14 @@
public class StatementImpl implements JdbcStatement {
protected static final String PING_MARKER = "/* ping */";
- protected NativeMessageBuilder commandBuilder = new NativeMessageBuilder(); // TODO use shared builder
-
public final static byte USES_VARIABLES_FALSE = 0;
public final static byte USES_VARIABLES_TRUE = 1;
public final static byte USES_VARIABLES_UNKNOWN = -1;
+ protected NativeMessageBuilder commandBuilder = null; // TODO use shared builder
+
/** The character encoding to use (if available) */
protected String charEncoding = null;
@@ -211,6 +212,8 @@ public StatementImpl(JdbcConnection c, String db) throws SQLException {
this.session = (NativeSession) c.getSession();
this.exceptionInterceptor = c.getExceptionInterceptor();
+ this.commandBuilder = new NativeMessageBuilder(this.session.getServerSession().supportsQueryAttributes());
+
try {
initQuery();
} catch (CJException e) {
@@ -286,15 +289,14 @@ public void cancel() throws SQLException {
}
if (!this.isClosed && this.connection != null) {
- JdbcConnection cancelConn = null;
- java.sql.Statement cancelStmt = null;
+ NativeSession newSession = null;
try {
HostInfo hostInfo = this.session.getHostInfo();
String database = hostInfo.getDatabase();
String user = hostInfo.getUser();
String password = hostInfo.getPassword();
- NativeSession newSession = new NativeSession(this.session.getHostInfo(), this.session.getPropertySet());
+ newSession = new NativeSession(this.session.getHostInfo(), this.session.getPropertySet());
newSession.connect(hostInfo, user, password, database, 30000, new TransactionEventHandler() {
@Override
public void transactionCompleted() {
@@ -304,18 +306,14 @@ public void transactionCompleted() {
public void transactionBegun() {
}
});
- newSession.sendCommand(new NativeMessageBuilder().buildComQuery(newSession.getSharedSendPacket(), "KILL QUERY " + this.session.getThreadId()),
- false, 0);
+ newSession.sendCommand(new NativeMessageBuilder(newSession.getServerSession().supportsQueryAttributes())
+ .buildComQuery(newSession.getSharedSendPacket(), "KILL QUERY " + this.session.getThreadId()), false, 0);
setCancelStatus(CancelStatus.CANCELED_BY_USER);
} catch (IOException e) {
throw SQLExceptionsMapping.translateException(e, this.exceptionInterceptor);
} finally {
- if (cancelStmt != null) {
- cancelStmt.close();
- }
-
- if (cancelConn != null) {
- cancelConn.close();
+ if (newSession != null) {
+ newSession.forceClose();
}
}
@@ -342,29 +340,29 @@ protected JdbcConnection checkClosed() {
}
/**
- * Checks if the given SQL query with the given first non-ws char is a DML
- * statement. Throws an exception if it is.
+ * Checks if the given SQL query is a result set producing query.
*
* @param sql
* the SQL to check
- * @param firstStatementChar
- * the UC first non-ws char of the statement
+ * @return
+ * true
if the query produces a result set, false
otherwise.
+ */
+ protected boolean isResultSetProducingQuery(String sql) {
+ QueryReturnType queryReturnType = ParseInfo.getQueryReturnType(sql, this.session.getServerSession().isNoBackslashEscapesSet());
+ return queryReturnType == QueryReturnType.PRODUCES_RESULT_SET || queryReturnType == QueryReturnType.MAY_PRODUCE_RESULT_SET;
+ }
+
+ /**
+ * Checks if the given SQL query does not return a result set.
*
- * @throws SQLException
- * if the statement contains DML
+ * @param sql
+ * the SQL to check
+ * @return
+ * true
if the query does not produce a result set, false
otherwise.
*/
- protected void checkForDml(String sql, char firstStatementChar) throws SQLException {
- if ((firstStatementChar == 'I') || (firstStatementChar == 'U') || (firstStatementChar == 'D') || (firstStatementChar == 'A')
- || (firstStatementChar == 'C') || (firstStatementChar == 'T') || (firstStatementChar == 'R')) {
- String noCommentSql = StringUtils.stripComments(sql, "'\"", "'\"", true, false, true, true);
-
- if (StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "INSERT") || StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "UPDATE")
- || StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "DELETE") || StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "DROP")
- || StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "CREATE") || StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "ALTER")
- || StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "TRUNCATE") || StringUtils.startsWithIgnoreCaseAndWs(noCommentSql, "RENAME")) {
- throw SQLError.createSQLException(Messages.getString("Statement.57"), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
- }
- }
+ protected boolean isNonResultSetProducingQuery(String sql) {
+ QueryReturnType queryReturnType = ParseInfo.getQueryReturnType(sql, this.session.getServerSession().isNoBackslashEscapesSet());
+ return queryReturnType == QueryReturnType.DOES_NOT_PRODUCE_RESULT_SET || queryReturnType == QueryReturnType.MAY_PRODUCE_RESULT_SET;
}
/**
@@ -554,6 +552,10 @@ private ResultSetInternalMethods createResultSetUsingServerFetch(String sql) thr
pStmt.setFetchSize(this.query.getResultFetchSize());
+ if (this.getQueryTimeout() > 0) {
+ pStmt.setQueryTimeout(this.getQueryTimeout());
+ }
+
if (this.maxRows > -1) {
pStmt.setMaxRows(this.maxRows);
}
@@ -666,14 +668,13 @@ private boolean executeInternal(String sql, boolean returnGeneratedKeys) throws
}
}
- char firstNonWsChar = StringUtils.firstAlphaCharUc(sql, findStartOfStatement(sql));
- boolean maybeSelect = firstNonWsChar == 'S';
-
this.retrieveGeneratedKeys = returnGeneratedKeys;
- this.lastQueryIsOnDupKeyUpdate = returnGeneratedKeys && firstNonWsChar == 'I' && containsOnDuplicateKeyInString(sql);
+ this.lastQueryIsOnDupKeyUpdate = returnGeneratedKeys
+ && ParseInfo.firstCharOfStatementUc(sql, this.session.getServerSession().isNoBackslashEscapesSet()) == 'I'
+ && containsOnDuplicateKeyInString(sql);
- if (!maybeSelect && locallyScopedConn.isReadOnly()) {
+ if (!ParseInfo.isReadOnlySafeQuery(sql, this.session.getServerSession().isNoBackslashEscapesSet()) && locallyScopedConn.isReadOnly()) {
throw SQLError.createSQLException(Messages.getString("Statement.27") + Messages.getString("Statement.28"),
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
@@ -715,7 +716,7 @@ private boolean executeInternal(String sql, boolean returnGeneratedKeys) throws
}
// Only apply max_rows to selects
- locallyScopedConn.setSessionMaxRows(maybeSelect ? this.maxRows : -1);
+ locallyScopedConn.setSessionMaxRows(isResultSetProducingQuery(sql) ? this.maxRows : -1);
statementBegins();
@@ -744,7 +745,7 @@ private boolean executeInternal(String sql, boolean returnGeneratedKeys) throws
this.results = rs;
- rs.setFirstCharOfQuery(firstNonWsChar);
+ rs.setFirstCharOfQuery(ParseInfo.firstCharOfStatementUc(sql, this.session.getServerSession().isNoBackslashEscapesSet()));
if (rs.hasRows()) {
if (cachedMetaData != null) {
@@ -968,6 +969,8 @@ private long[] executeBatchUsingMultiQueries(boolean multiQueriesEnabled, int nb
StringBuilder queryBuf = new StringBuilder();
batchStmt = locallyScopedConn.createStatement();
+ JdbcStatement jdbcBatchedStmt = (JdbcStatement) batchStmt;
+ getQueryAttributesBindings().runThroughAll(a -> jdbcBatchedStmt.setAttribute(a.getName(), a.getValue()));
timeoutTask = startQueryTimer((StatementImpl) batchStmt, individualStatementTimeout);
@@ -976,14 +979,14 @@ private long[] executeBatchUsingMultiQueries(boolean multiQueriesEnabled, int nb
String connectionEncoding = locallyScopedConn.getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue();
int numberOfBytesPerChar = StringUtils.startsWithIgnoreCase(connectionEncoding, "utf") ? 3
- : (CharsetMapping.isMultibyteCharset(connectionEncoding) ? 2 : 1);
+ : (this.session.getServerSession().getCharsetSettings().isMultibyteCharset(connectionEncoding) ? 2 : 1);
int escapeAdjust = 1;
batchStmt.setEscapeProcessing(this.doEscapeProcessing);
if (this.doEscapeProcessing) {
- escapeAdjust = 2; // We assume packet _could_ grow by this amount, as we're not sure how big statement will end up after escape processing
+ escapeAdjust = 2; // We assume packet _could_ grow by this amount, as we're not sure how big statement will end up after escape processing
}
SQLException sqlEx = null;
@@ -1128,9 +1131,9 @@ public java.sql.ResultSet executeQuery(String sql) throws SQLException {
sql = escapedSqlResult instanceof String ? (String) escapedSqlResult : ((EscapeProcessorResult) escapedSqlResult).escapedSql;
}
- char firstStatementChar = StringUtils.firstAlphaCharUc(sql, findStartOfStatement(sql));
-
- checkForDml(sql, firstStatementChar);
+ if (!isResultSetProducingQuery(sql)) {
+ throw SQLError.createSQLException(Messages.getString("Statement.57"), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
+ }
CachedResultSetMetaData cachedMetaData = null;
@@ -1219,8 +1222,8 @@ protected void doPingInstead() throws SQLException {
protected ResultSetInternalMethods generatePingResultSet() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
- String encoding = this.session.getServerSession().getCharacterSetMetadata();
- int collationIndex = this.session.getServerSession().getMetadataCollationIndex();
+ String encoding = this.session.getServerSession().getCharsetSettings().getMetadataEncoding();
+ int collationIndex = this.session.getServerSession().getCharsetSettings().getMetadataCollationIndex();
Field[] fields = { new Field(null, "1", collationIndex, encoding, MysqlType.BIGINT, 1) };
ArrayList rows = new ArrayList<>();
byte[] colVal = new byte[] { (byte) '1' };
@@ -1251,7 +1254,10 @@ protected long executeUpdateInternal(String sql, boolean isBatch, boolean return
resetCancelledState();
- char firstStatementChar = StringUtils.firstAlphaCharUc(sql, findStartOfStatement(sql));
+ char firstStatementChar = ParseInfo.firstCharOfStatementUc(sql, this.session.getServerSession().isNoBackslashEscapesSet());
+ if (!isNonResultSetProducingQuery(sql)) {
+ throw SQLError.createSQLException(Messages.getString("Statement.46"), "01S03", getExceptionInterceptor());
+ }
this.retrieveGeneratedKeys = returnGeneratedKeys;
@@ -1271,10 +1277,6 @@ protected long executeUpdateInternal(String sql, boolean isBatch, boolean return
MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}
- if (StringUtils.startsWithIgnoreCaseAndWs(sql, "select")) {
- throw SQLError.createSQLException(Messages.getString("Statement.46"), "01S03", getExceptionInterceptor());
- }
-
implicitlyCloseAllOpenResults();
// The checking and changing of databases must happen in sequence, so synchronize on the same mutex that _conn is using
@@ -1382,8 +1384,8 @@ public java.sql.ResultSet getGeneratedKeys() throws SQLException {
return this.generatedKeysResults = getGeneratedKeysInternal();
}
- String encoding = this.session.getServerSession().getCharacterSetMetadata();
- int collationIndex = this.session.getServerSession().getMetadataCollationIndex();
+ String encoding = this.session.getServerSession().getCharsetSettings().getMetadataEncoding();
+ int collationIndex = this.session.getServerSession().getCharsetSettings().getMetadataCollationIndex();
Field[] fields = new Field[1];
fields[0] = new Field("", "GENERATED_KEY", collationIndex, encoding, MysqlType.BIGINT_UNSIGNED, 20);
@@ -1406,8 +1408,8 @@ protected ResultSetInternalMethods getGeneratedKeysInternal() throws SQLExceptio
protected ResultSetInternalMethods getGeneratedKeysInternal(long numKeys) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
- String encoding = this.session.getServerSession().getCharacterSetMetadata();
- int collationIndex = this.session.getServerSession().getMetadataCollationIndex();
+ String encoding = this.session.getServerSession().getCharsetSettings().getMetadataEncoding();
+ int collationIndex = this.session.getServerSession().getCharsetSettings().getMetadataCollationIndex();
Field[] fields = new Field[1];
fields[0] = new Field("", "GENERATED_KEY", collationIndex, encoding, MysqlType.BIGINT_UNSIGNED, 20);
@@ -1728,7 +1730,7 @@ public java.sql.SQLWarning getWarnings() throws SQLException {
return null;
}
- SQLWarning pendingWarningsFromServer = this.session.getProtocol().convertShowWarningsToSQLWarnings(0, false);
+ SQLWarning pendingWarningsFromServer = this.session.getProtocol().convertShowWarningsToSQLWarnings(false);
if (this.warningChain != null) {
this.warningChain.setNextWarning(pendingWarningsFromServer);
@@ -1794,6 +1796,8 @@ protected void realClose(boolean calledExplicitly, boolean closeOpenResults) thr
closeAllOpenResults();
}
+ clearAttributes();
+
this.isClosed = true;
closeQuery();
@@ -2029,32 +2033,6 @@ public T unwrap(Class iface) throws SQLException {
}
}
- protected static int findStartOfStatement(String sql) {
- int statementStartPos = 0;
-
- if (StringUtils.startsWithIgnoreCaseAndWs(sql, "/*")) {
- statementStartPos = sql.indexOf("*/");
-
- if (statementStartPos == -1) {
- statementStartPos = 0;
- } else {
- statementStartPos += 2;
- }
- } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "--") || StringUtils.startsWithIgnoreCaseAndWs(sql, "#")) {
- statementStartPos = sql.indexOf('\n');
-
- if (statementStartPos == -1) {
- statementStartPos = sql.indexOf('\r');
-
- if (statementStartPos == -1) {
- statementStartPos = 0;
- }
- }
- }
-
- return statementStartPos;
- }
-
@Override
public InputStream getLocalInfileInputStream() {
return this.session.getLocalInfileInputStream();
@@ -2269,4 +2247,19 @@ public void setClearWarningsCalled(boolean clearWarningsCalled) {
public Query getQuery() {
return this.query;
}
+
+ @Override
+ public QueryAttributesBindings getQueryAttributesBindings() {
+ return this.query.getQueryAttributesBindings();
+ }
+
+ @Override
+ public void setAttribute(String name, Object value) {
+ getQueryAttributesBindings().setAttribute(name, value);
+ }
+
+ @Override
+ public void clearAttributes() {
+ getQueryAttributesBindings().clearAttributes();
+ }
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/FailoverConnectionProxy.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/FailoverConnectionProxy.java
index 7ad584957..635aad8e5 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/FailoverConnectionProxy.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/FailoverConnectionProxy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2010, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -499,7 +499,7 @@ synchronized void doAbort(Executor executor) throws SQLException {
* This is the continuation of MultiHostConnectionProxy#invoke(Object, Method, Object[]).
*/
@Override
- public synchronized Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
+ public Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (METHOD_SET_READ_ONLY.equals(methodName)) {
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/LoadBalancedConnectionProxy.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/LoadBalancedConnectionProxy.java
index c9db2bdde..eb3c1c2c1 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/LoadBalancedConnectionProxy.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/LoadBalancedConnectionProxy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2007, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -536,7 +536,7 @@ synchronized void doAbort(Executor executor) {
* This is the continuation of MultiHostConnectionProxy#invoke(Object, Method, Object[]).
*/
@Override
- public synchronized Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
+ Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (this.isClosed && !allowedOnClosedConnection(method) && method.getExceptionTypes().length > 0) { // TODO remove method.getExceptionTypes().length ?
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostConnectionProxy.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostConnectionProxy.java
index f9bf0800a..ab7d8184b 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostConnectionProxy.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostConnectionProxy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -54,7 +54,6 @@
public abstract class MultiHostConnectionProxy implements InvocationHandler {
private static final String METHOD_GET_MULTI_HOST_SAFE_PROXY = "getMultiHostSafeProxy";
private static final String METHOD_EQUALS = "equals";
- private static final String METHOD_HASH_CODE = "hashCode";
private static final String METHOD_CLOSE = "close";
private static final String METHOD_ABORT_INTERNAL = "abortInternal";
private static final String METHOD_ABORT = "abort";
@@ -466,7 +465,7 @@ void syncSessionState(JdbcConnection source, JdbcConnection target, boolean read
* if an error occurs
*/
@Override
- public synchronized Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (METHOD_GET_MULTI_HOST_SAFE_PROXY.equals(methodName)) {
@@ -478,50 +477,53 @@ public synchronized Object invoke(Object proxy, Method method, Object[] args) th
return args[0].equals(this);
}
- if (METHOD_HASH_CODE.equals(methodName)) {
- return this.hashCode();
+ // Execute remaining ubiquitous methods right away.
+ if (method.getDeclaringClass().equals(Object.class)) {
+ return method.invoke(this, args);
}
- if (METHOD_CLOSE.equals(methodName)) {
- doClose();
- this.isClosed = true;
- this.closedReason = "Connection explicitly closed.";
- this.closedExplicitly = true;
- return null;
- }
+ synchronized (this) {
+ if (METHOD_CLOSE.equals(methodName)) {
+ doClose();
+ this.isClosed = true;
+ this.closedReason = "Connection explicitly closed.";
+ this.closedExplicitly = true;
+ return null;
+ }
- if (METHOD_ABORT_INTERNAL.equals(methodName)) {
- doAbortInternal();
- this.currentConnection.abortInternal();
- this.isClosed = true;
- this.closedReason = "Connection explicitly closed.";
- return null;
- }
+ if (METHOD_ABORT_INTERNAL.equals(methodName)) {
+ doAbortInternal();
+ this.currentConnection.abortInternal();
+ this.isClosed = true;
+ this.closedReason = "Connection explicitly closed.";
+ return null;
+ }
- if (METHOD_ABORT.equals(methodName) && args.length == 1) {
- doAbort((Executor) args[0]);
- this.isClosed = true;
- this.closedReason = "Connection explicitly closed.";
- return null;
- }
+ if (METHOD_ABORT.equals(methodName) && args.length == 1) {
+ doAbort((Executor) args[0]);
+ this.isClosed = true;
+ this.closedReason = "Connection explicitly closed.";
+ return null;
+ }
- if (METHOD_IS_CLOSED.equals(methodName)) {
- return this.isClosed;
- }
+ if (METHOD_IS_CLOSED.equals(methodName)) {
+ return this.isClosed;
+ }
- try {
- return invokeMore(proxy, method, args);
- } catch (InvocationTargetException e) {
- throw e.getCause() != null ? e.getCause() : e;
- } catch (Exception e) {
- // Check if the captured exception must be wrapped by an unchecked exception.
- Class>[] declaredException = method.getExceptionTypes();
- for (Class> declEx : declaredException) {
- if (declEx.isAssignableFrom(e.getClass())) {
- throw e;
+ try {
+ return invokeMore(proxy, method, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause() != null ? e.getCause() : e;
+ } catch (Exception e) {
+ // Check if the captured exception must be wrapped by an unchecked exception.
+ Class>[] declaredException = method.getExceptionTypes();
+ for (Class> declEx : declaredException) {
+ if (declEx.isAssignableFrom(e.getClass())) {
+ throw e;
+ }
}
+ throw new IllegalStateException(e.getMessage(), e);
}
- throw new IllegalStateException(e.getMessage(), e);
}
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostMySQLConnection.java b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostMySQLConnection.java
index c379c4f2d..7b1042b15 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostMySQLConnection.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostMySQLConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -60,6 +60,7 @@
import com.mysql.cj.jdbc.exceptions.SQLError;
import com.mysql.cj.jdbc.result.CachedResultSetMetaData;
import com.mysql.cj.jdbc.result.ResultSetInternalMethods;
+import com.mysql.cj.protocol.ServerSessionStateController;
/**
* Each instance of MultiHostMySQLConnection is coupled with a MultiHostConnectionProxy instance.
@@ -753,4 +754,9 @@ public void normalClose() {
public void cleanup(Throwable whyCleanedUp) {
getActiveMySQLConnection().cleanup(whyCleanedUp);
}
+
+ @Override
+ public ServerSessionStateController getServerSessionStateController() {
+ return getActiveMySQLConnection().getServerSessionStateController();
+ }
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetImpl.java b/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetImpl.java
index 10606d9cd..ff45a5592 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetImpl.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetImpl.java
@@ -371,6 +371,11 @@ public void initializeWithMetadata() throws SQLException {
@Override
public boolean absolute(int row) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
if (isStrictlyForwardOnly()) {
throw ExceptionFactory.createException(Messages.getString("ResultSet.ForwardOnly"));
}
@@ -419,6 +424,11 @@ public boolean absolute(int row) throws SQLException {
@Override
public void afterLast() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
if (isStrictlyForwardOnly()) {
throw ExceptionFactory.createException(Messages.getString("ResultSet.ForwardOnly"));
}
@@ -435,6 +445,11 @@ public void afterLast() throws SQLException {
@Override
public void beforeFirst() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
if (isStrictlyForwardOnly()) {
throw ExceptionFactory.createException(Messages.getString("ResultSet.ForwardOnly"));
}
@@ -560,18 +575,6 @@ public void deleteRow() throws SQLException {
throw new NotUpdatable(Messages.getString("NotUpdatable.0"));
}
- /*
- * /**
- * TODO: Required by JDBC spec
- */
- /*
- * protected void finalize() throws Throwable {
- * if (!this.isClosed) {
- * realClose(false);
- * }
- * }
- */
-
@Override
public int findColumn(String columnName) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
@@ -590,6 +593,11 @@ public int findColumn(String columnName) throws SQLException {
@Override
public boolean first() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
if (isStrictlyForwardOnly()) {
throw ExceptionFactory.createException(Messages.getString("ResultSet.ForwardOnly"));
}
@@ -875,7 +883,7 @@ public String getString(int columnIndex) throws SQLException {
String stringVal = this.thisRow.getValue(columnIndex - 1, vf);
if (this.padCharsWithSpace && stringVal != null && f.getMysqlTypeId() == MysqlType.FIELD_TYPE_STRING) {
- int maxBytesPerChar = this.session.getServerSession().getMaxBytesPerChar(f.getCollationIndex(), f.getEncoding());
+ int maxBytesPerChar = this.session.getServerSession().getCharsetSettings().getMaxBytesPerChar(f.getCollationIndex(), f.getEncoding());
int fieldLength = (int) f.getLength() /* safe, bytes in a CHAR <= 1024 */ / maxBytesPerChar; /* safe, this will never be 0 */
return StringUtils.padString(stringVal, fieldLength);
}
@@ -1343,7 +1351,8 @@ public T getObject(int columnIndex, Class type) throws SQLException {
return (T) getTimestamp(columnIndex);
} else if (type.equals(java.util.Date.class)) {
- return (T) java.util.Date.from(getTimestamp(columnIndex).toInstant());
+ Timestamp ts = getTimestamp(columnIndex);
+ return ts == null ? null : (T) java.util.Date.from(ts.toInstant());
} else if (type.equals(java.util.Calendar.class)) {
return (T) getUtilCalendar(columnIndex);
@@ -1589,6 +1598,11 @@ public java.sql.Ref getRef(String colName) throws SQLException {
public int getRow() throws SQLException {
checkClosed();
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"), MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR,
+ getExceptionInterceptor());
+ }
+
int currentRowNumber = this.rowData.getPosition();
int row = 0;
@@ -1691,15 +1705,22 @@ public void insertRow() throws SQLException {
@Override
public boolean isAfterLast() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
- boolean b = this.rowData.isAfterLast();
-
- return b;
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+ return this.rowData.isAfterLast();
}
}
@Override
public boolean isBeforeFirst() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
return this.rowData.isBeforeFirst();
}
}
@@ -1707,6 +1728,11 @@ public boolean isBeforeFirst() throws SQLException {
@Override
public boolean isFirst() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
return this.rowData.isFirst();
}
}
@@ -1714,6 +1740,11 @@ public boolean isFirst() throws SQLException {
@Override
public boolean isLast() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
return this.rowData.isLast();
}
}
@@ -1732,6 +1763,11 @@ protected boolean isStrictlyForwardOnly() {
@Override
public boolean last() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
if (isStrictlyForwardOnly()) {
throw ExceptionFactory.createException(Messages.getString("ResultSet.ForwardOnly"));
}
@@ -1764,14 +1800,13 @@ public void moveToInsertRow() throws SQLException {
@Override
public boolean next() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
-
- boolean b;
-
if (!hasRows()) {
throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
+ boolean b;
+
if (this.rowData.size() == 0) {
b = false;
} else {
@@ -1838,6 +1873,11 @@ public boolean prev() throws java.sql.SQLException {
@Override
public boolean previous() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
if (isStrictlyForwardOnly()) {
throw ExceptionFactory.createException(Messages.getString("ResultSet.ForwardOnly"));
}
@@ -1960,6 +2000,11 @@ public void refreshRow() throws SQLException {
@Override
public boolean relative(int rows) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
+ if (!hasRows()) {
+ throw SQLError.createSQLException(Messages.getString("ResultSet.ResultSet_is_from_UPDATE._No_Data_115"),
+ MysqlErrorNumbers.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
+ }
+
if (isStrictlyForwardOnly()) {
throw ExceptionFactory.createException(Messages.getString("ResultSet.ForwardOnly"));
}
diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetMetaData.java b/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetMetaData.java
index b89172e32..155e98d2a 100644
--- a/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetMetaData.java
+++ b/src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetMetaData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -31,10 +31,8 @@
import java.sql.SQLException;
-import com.mysql.cj.CharsetMapping;
import com.mysql.cj.Messages;
import com.mysql.cj.MysqlType;
-import com.mysql.cj.NativeSession;
import com.mysql.cj.Session;
import com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm;
import com.mysql.cj.conf.PropertyKey;
@@ -127,18 +125,7 @@ public String getColumnCharacterEncoding(int column) throws SQLException {
* if an invalid column index is given.
*/
public String getColumnCharacterSet(int column) throws SQLException {
- int index = getField(column).getCollationIndex();
-
- String charsetName = null;
-
- if (((NativeSession) this.session).getProtocol().getServerSession().indexToCustomMysqlCharset != null) {
- charsetName = ((NativeSession) this.session).getProtocol().getServerSession().indexToCustomMysqlCharset.get(index);
- }
- if (charsetName == null) {
- charsetName = CharsetMapping.getMysqlCharsetNameForCollationIndex(index);
- }
-
- return charsetName;
+ return this.session.getServerSession().getCharsetSettings().getMysqlCharsetNameForCollationIndex(getField(column).getCollationIndex());
}
@Override
@@ -169,7 +156,7 @@ public int getColumnDisplaySize(int column) throws SQLException {
int lengthInBytes = clampedGetLength(f);
- return lengthInBytes / this.session.getServerSession().getMaxBytesPerChar(f.getCollationIndex(), f.getEncoding());
+ return lengthInBytes / this.session.getServerSession().getCharsetSettings().getMaxBytesPerChar(f.getCollationIndex(), f.getEncoding());
}
@Override
@@ -241,7 +228,7 @@ public int getPrecision(int column) throws SQLException {
default:
return f.getMysqlType().isDecimal() ? clampedGetLength(f)
- : clampedGetLength(f) / this.session.getServerSession().getMaxBytesPerChar(f.getCollationIndex(), f.getEncoding());
+ : clampedGetLength(f) / this.session.getServerSession().getCharsetSettings().getMaxBytesPerChar(f.getCollationIndex(), f.getEncoding());
}
}
@@ -315,7 +302,7 @@ public boolean isCaseSensitive(int column) throws java.sql.SQLException {
case JSON:
case ENUM:
case SET:
- String collationName = CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[field.getCollationIndex()];
+ String collationName = this.session.getServerSession().getCharsetSettings().getCollationNameForCollationIndex(field.getCollationIndex());
return ((collationName != null) && !collationName.endsWith("_ci"));
default:
diff --git a/src/main/user-impl/java/com/mysql/cj/xdevapi/CollectionImpl.java b/src/main/user-impl/java/com/mysql/cj/xdevapi/CollectionImpl.java
index 5883498d3..43eae5edb 100644
--- a/src/main/user-impl/java/com/mysql/cj/xdevapi/CollectionImpl.java
+++ b/src/main/user-impl/java/com/mysql/cj/xdevapi/CollectionImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -188,6 +188,10 @@ public Result replaceOne(String id, DbDoc doc) {
if (doc == null) {
throw new XDevAPIError(Messages.getString("CreateTableStatement.0", new String[] { "doc" }));
}
+ JsonValue docId = doc.get("_id");
+ if (docId != null && (!JsonString.class.isInstance(docId) || !id.equals(((JsonString) docId).getString()))) {
+ throw new XDevAPIError(Messages.getString("Collection.DocIdMismatch"));
+ }
return modify("_id = :id").set("$", doc).bind("id", id).execute();
}
@@ -214,10 +218,11 @@ public Result addOrReplaceOne(String id, DbDoc doc) {
if (doc == null) {
throw new XDevAPIError(Messages.getString("CreateTableStatement.0", new String[] { "doc" }));
}
- if (doc.get("_id") == null) {
+ JsonValue docId = doc.get("_id");
+ if (docId == null) {
doc.add("_id", new JsonString().setValue(id));
- } else if (!id.equals(((JsonString) doc.get("_id")).getString())) {
- throw new XDevAPIError("Document already has an _id that doesn't match to id parameter");
+ } else if (!JsonString.class.isInstance(docId) || !id.equals(((JsonString) docId).getString())) {
+ throw new XDevAPIError(Messages.getString("Collection.DocIdMismatch"));
}
return add(doc).setUpsert(true).execute();
}
diff --git a/src/main/user-impl/java/com/mysql/cj/xdevapi/ColumnImpl.java b/src/main/user-impl/java/com/mysql/cj/xdevapi/ColumnImpl.java
index 902017707..8cccf54c6 100644
--- a/src/main/user-impl/java/com/mysql/cj/xdevapi/ColumnImpl.java
+++ b/src/main/user-impl/java/com/mysql/cj/xdevapi/ColumnImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -151,11 +151,11 @@ public boolean isNumberSigned() {
}
public String getCollationName() {
- return CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[this.field.getCollationIndex()];
+ return CharsetMapping.getStaticCollationNameForCollationIndex(this.field.getCollationIndex()); // TODO use CharsetSettings method
}
public String getCharacterSetName() {
- return CharsetMapping.getMysqlCharsetNameForCollationIndex(this.field.getCollationIndex());
+ return CharsetMapping.getStaticMysqlCharsetNameForCollationIndex(this.field.getCollationIndex()); // TODO use CharsetSettings method
}
public boolean isPadded() {
diff --git a/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingDocResultBuilder.java b/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingDocResultBuilder.java
index fc443bf9c..825a11766 100644
--- a/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingDocResultBuilder.java
+++ b/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingDocResultBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2019, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -70,6 +70,7 @@ public boolean addProtocolEntity(ProtocolEntity entity) {
} else if (entity instanceof Notice) {
this.statementExecuteOkBuilder.addProtocolEntity(entity);
+ return false;
}
if (this.metadata == null) {
diff --git a/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingSqlResultBuilder.java b/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingSqlResultBuilder.java
index d36ff5e65..bd8a210a0 100644
--- a/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingSqlResultBuilder.java
+++ b/src/main/user-impl/java/com/mysql/cj/xdevapi/StreamingSqlResultBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2019, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -102,7 +102,7 @@ public boolean addProtocolEntity(ProtocolEntity entity) {
});
this.lastEntity = null;
} else {
- cd = this.protocol.readMetadata();
+ cd = this.protocol.readMetadata(this.statementExecuteOkBuilder::addProtocolEntity);
}
return new SqlSingleResult(cd, this.protocol.getServerSession().getDefaultTimeZone(), new XProtocolRowInputStream(cd, this.protocol, (n) -> {
this.statementExecuteOkBuilder.addProtocolEntity(n);
diff --git a/src/test/java/com/mysql/cj/CharsetMappingWrapper.java b/src/test/java/com/mysql/cj/CharsetMappingWrapper.java
new file mode 100644
index 000000000..074ab2c2a
--- /dev/null
+++ b/src/test/java/com/mysql/cj/CharsetMappingWrapper.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is also distributed with certain software (including but not
+ * limited to OpenSSL) that is licensed under separate terms, as designated in a
+ * particular file or component or in included license documentation. The
+ * authors of MySQL hereby grant you an additional permission to link the
+ * program and your derivative works with the separately licensed software that
+ * they have included with MySQL.
+ *
+ * Without limiting anything contained in the foregoing, this file, which is
+ * part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
+ * version 1.0, a copy of which can be found at
+ * http://oss.oracle.com/licenses/universal-foss-exception.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package com.mysql.cj;
+
+/**
+ * Exposes protected {@link CharsetMapping} methods for use in tests.
+ */
+public class CharsetMappingWrapper {
+
+ public static boolean isStaticMultibyteCharset(String javaEncodingName) {
+ return CharsetMapping.isStaticMultibyteCharset(javaEncodingName);
+ }
+
+ public static int getStaticCollationIndexForJavaEncoding(String javaEncoding, ServerVersion version) {
+ return CharsetMapping.getStaticCollationIndexForJavaEncoding(javaEncoding, version);
+ }
+
+ public static String getStaticCollationNameForCollationIndex(Integer collationIndex) {
+ return CharsetMapping.getStaticCollationNameForCollationIndex(collationIndex);
+ }
+
+ public static String getStaticJavaEncodingForCollationIndex(Integer collationIndex) {
+ return CharsetMapping.getStaticJavaEncodingForCollationIndex(collationIndex);
+ }
+
+ public static String getStaticJavaEncodingForMysqlCharset(String mysqlCharsetName) {
+ return CharsetMapping.getStaticJavaEncodingForMysqlCharset(mysqlCharsetName);
+ }
+
+ public static String getStaticMysqlCharsetByName(String mysqlCharsetName) {
+ Object cs = CharsetMapping.getStaticMysqlCharsetByName(mysqlCharsetName);
+ return cs == null ? null : cs.toString();
+ }
+
+ public static String getStaticMysqlCharsetForJavaEncoding(String javaEncoding, ServerVersion version) {
+ return CharsetMapping.getStaticMysqlCharsetForJavaEncoding(javaEncoding, version);
+ }
+
+ public static String getStaticMysqlCharsetNameForCollationIndex(Integer collationIndex) {
+ return CharsetMapping.getStaticMysqlCharsetNameForCollationIndex(collationIndex);
+ }
+
+}
diff --git a/src/test/java/com/mysql/cj/ConnectionUrlTest.java b/src/test/java/com/mysql/cj/ConnectionUrlTest.java
index 62ee30b06..38ab7d0b9 100644
--- a/src/test/java/com/mysql/cj/ConnectionUrlTest.java
+++ b/src/test/java/com/mysql/cj/ConnectionUrlTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -96,14 +96,10 @@ protected static EX assertThrows(String message, Class {
System.out.println(ConnectionUrl.getConnectionUrlInstance(cs, null));
- fail(cs + ": expected to throw a " + WrongArgumentException.class.getName());
- } catch (Exception e) {
- assertTrue(WrongArgumentException.class.isAssignableFrom(e.getClass()), cs + ": expected to throw a " + WrongArgumentException.class.getName());
- }
+ return null;
+ });
}
}
diff --git a/src/test/java/com/mysql/cj/MessagesTest.java b/src/test/java/com/mysql/cj/MessagesTest.java
index 183fb21fe..745aca9cb 100644
--- a/src/test/java/com/mysql/cj/MessagesTest.java
+++ b/src/test/java/com/mysql/cj/MessagesTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -104,9 +104,10 @@ public void testLocalizedErrorMessages() throws Exception {
assertEquals("Illegal starting position for search, '10'", Messages.getString("Clob.8", new Object[] { 10 }));
- assertEquals("Java does not support the MySQL character encoding 'Test'.", Messages.getString("Connection.5", new Object[] { "Test" }));
+ assertEquals("Unknown Java encoding for the character set with index '1234'. Use the 'customCharsetMapping' property to force it.",
+ Messages.getString("Connection.5", new Object[] { "1234" }));
assertEquals(
- "Unknown initial character set index 'Test' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
+ "Unknown character set index 'Test' received from server. The appropriate client character set can be forced via the 'characterEncoding' property.",
Messages.getString("Connection.6", new Object[] { "Test" }));
assertEquals("Can't map Test given for characterSetResults to a supported MySQL encoding.",
Messages.getString("Connection.7", new Object[] { "Test" }));
diff --git a/src/test/java/com/mysql/cj/protocol/a/MysqlTextValueDecoderTest.java b/src/test/java/com/mysql/cj/protocol/a/MysqlTextValueDecoderTest.java
index 70c00f463..ff866f190 100644
--- a/src/test/java/com/mysql/cj/protocol/a/MysqlTextValueDecoderTest.java
+++ b/src/test/java/com/mysql/cj/protocol/a/MysqlTextValueDecoderTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -31,8 +31,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
@@ -96,12 +96,10 @@ public void testIntValues() {
assertEquals(String.valueOf(Integer.MAX_VALUE), this.valueDecoder.decodeUInt4(String.valueOf(Integer.MAX_VALUE).getBytes(), 0, 10, vf));
assertEquals("2147483648",
this.valueDecoder.decodeUInt4(Constants.BIG_INTEGER_MAX_INTEGER_VALUE.add(Constants.BIG_INTEGER_ONE).toString().getBytes(), 0, 10, vf));
- try {
+
+ assertThrows(NumberOutOfRange.class, () -> {
this.valueDecoder.decodeInt4(Constants.BIG_INTEGER_MAX_INTEGER_VALUE.add(Constants.BIG_INTEGER_ONE).toString().getBytes(), 0, 10, vf);
- fail("Exception should be thrown for decodeInt4(Integer.MAX_VALUE + 1)");
- } catch (NumberOutOfRange ex) {
- // expected
- }
+ }, "Exception should be thrown for decodeInt4(Integer.MAX_VALUE + 1)");
byte[] uint8LessThanMaxLong = "8223372036854775807".getBytes();
ValueFactory fromLongOnly = new DefaultValueFactory(new DefaultPropertySet()) {
diff --git a/src/test/java/com/mysql/cj/protocol/a/SimplePacketReaderTest.java b/src/test/java/com/mysql/cj/protocol/a/SimplePacketReaderTest.java
index 269877166..b041b210e 100644
--- a/src/test/java/com/mysql/cj/protocol/a/SimplePacketReaderTest.java
+++ b/src/test/java/com/mysql/cj/protocol/a/SimplePacketReaderTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2016, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -241,8 +241,6 @@ public void connect(String host, int port, PropertySet propertySet, ExceptionInt
@Override
public void performTlsHandshake(ServerSession serverSession) throws SSLParamsException, FeatureNotAvailableException, IOException {
- // TODO Auto-generated method stub
-
}
public void forceClose() {
diff --git a/src/test/java/com/mysql/cj/protocol/x/SyncMessageWriterTest.java b/src/test/java/com/mysql/cj/protocol/x/SyncMessageWriterTest.java
index 09219e014..41b9f3990 100644
--- a/src/test/java/com/mysql/cj/protocol/x/SyncMessageWriterTest.java
+++ b/src/test/java/com/mysql/cj/protocol/x/SyncMessageWriterTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -30,8 +30,8 @@
package com.mysql.cj.protocol.x;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
@@ -87,13 +87,10 @@ public void testCompleteWriteMessage() throws IOException {
@Test
public void testBadMessageClass() {
- try {
+ assertThrows(WrongArgumentException.class, () -> {
// try sending "Ok" which is a server-sent message. should fail with exception
this.writer.send(new XMessage(Ok.getDefaultInstance()));
- fail("Writing OK message should fail");
- } catch (WrongArgumentException ex) {
- // expected
- }
+ }, "Writing OK message should fail");
}
@Test
diff --git a/src/test/java/com/mysql/cj/result/CommonAsserts.java b/src/test/java/com/mysql/cj/result/CommonAsserts.java
index 45ffbebec..123eb3381 100644
--- a/src/test/java/com/mysql/cj/result/CommonAsserts.java
+++ b/src/test/java/com/mysql/cj/result/CommonAsserts.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -29,6 +29,7 @@
package com.mysql.cj.result;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.concurrent.Callable;
@@ -38,14 +39,9 @@ protected static EX assertThrows(Class throwable, Str
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.");
- }
-
- if (!t.getMessage().matches(msgMatchesRegex)) {
- fail("The error message [" + t.getMessage() + "] was expected to match [" + msgMatchesRegex + "].");
- }
-
+ assertTrue(throwable.isAssignableFrom(t.getClass()),
+ "Expected exception of type '" + throwable.getName() + "' but instead a exception of type '" + t.getClass().getName() + "' was thrown.");
+ assertTrue(t.getMessage().matches(msgMatchesRegex), "The error message [" + t.getMessage() + "] was expected to match [" + msgMatchesRegex + "].");
return throwable.cast(t);
}
fail("Expected exception of type '" + throwable.getName() + "'.");
diff --git a/src/test/java/testsuite/simple/StringUtilsTest.java b/src/test/java/com/mysql/cj/util/StringUtilsTest.java
similarity index 82%
rename from src/test/java/testsuite/simple/StringUtilsTest.java
rename to src/test/java/com/mysql/cj/util/StringUtilsTest.java
index 8094a982a..b58c94451 100644
--- a/src/test/java/testsuite/simple/StringUtilsTest.java
+++ b/src/test/java/com/mysql/cj/util/StringUtilsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -27,7 +27,7 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-package testsuite.simple;
+package com.mysql.cj.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -44,10 +44,6 @@
import org.junit.jupiter.api.Test;
-import com.mysql.cj.util.LazyString;
-import com.mysql.cj.util.StringUtils;
-import com.mysql.cj.util.StringUtils.SearchMode;
-
import testsuite.BaseTestCase;
public class StringUtilsTest extends BaseTestCase {
@@ -112,21 +108,27 @@ public void testIndexOfIgnoreCase() throws Exception {
/*
* C. test indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, String openingMarkers, String closingMarkers, Set
- * searchMode) using search modes SEARCH_MODE__BSESC_MRK_WS or SEARCH_MODE__MRK_WS
+ * searchMode) using search modes SearchMode.__MRK_WS or SearchMode.__BSE_MRK_WS
*/
// basic test set
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, null, (String) null, markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, null, "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", (String) null, markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "bcd", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(6, StringUtils.indexOfIgnoreCase(0, "ab -- abc", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(5, StringUtils.indexOfIgnoreCase(0, "ab # abc", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/*/* /c", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/**/c", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(5, StringUtils.indexOfIgnoreCase(0, "ab/* abc */c", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(0, StringUtils.indexOfIgnoreCase(0, "abc", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
- assertEquals(3, StringUtils.indexOfIgnoreCase(0, "abc d efg", " d ", markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS));
+ assertThrows(IllegalArgumentException.class, "The source string must not be null.", () -> {
+ StringUtils.indexOfIgnoreCase(0, null, (String) null, markerStart, markerEnd, SearchMode.__BSE_MRK_WS);
+ return null;
+ });
+ assertThrows(IllegalArgumentException.class, "The source string must not be null.", () -> {
+ StringUtils.indexOfIgnoreCase(0, null, "abc", markerStart, markerEnd, SearchMode.__BSE_MRK_WS);
+ return null;
+ });
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", (String) null, markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "bcd", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(6, StringUtils.indexOfIgnoreCase(0, "ab -- abc", "abc", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(5, StringUtils.indexOfIgnoreCase(0, "ab # abc", "abc", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/*/* /c", "abc", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/**/c", "abc", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(5, StringUtils.indexOfIgnoreCase(0, "ab/* abc */c", "abc", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(0, StringUtils.indexOfIgnoreCase(0, "abc", "abc", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
+ assertEquals(3, StringUtils.indexOfIgnoreCase(0, "abc d efg", " d ", markerStart, markerEnd, SearchMode.__BSE_MRK_WS));
// exhaustive test set
searchInMulti = new String[] { "A \"strange \"STRONG SsStRiNg to be searched in", "A 'strange 'STRONG SsStRiNg to be searched in",
@@ -136,18 +138,17 @@ public void testIndexOfIgnoreCase() throws Exception {
for (int i = 0; i < searchForMulti.length; i++) {
for (int j = 0; j < searchInMulti.length; j++) {
// multiple markers
- assertEquals(expectedIdx[i],
- StringUtils.indexOfIgnoreCase(0, searchInMulti[j], searchForMulti[i], markerStart, markerEnd, StringUtils.SEARCH_MODE__MRK_WS),
+ assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchInMulti[j], searchForMulti[i], markerStart, markerEnd, SearchMode.__MRK_WS),
"Test C." + j + "." + i);
assertEquals(expectedIdx[i],
- StringUtils.indexOfIgnoreCase(0, searchInMulti[j], searchForMulti[i], markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS),
+ StringUtils.indexOfIgnoreCase(0, searchInMulti[j], searchForMulti[i], markerStart, markerEnd, SearchMode.__BSE_MRK_WS),
"Test C." + j + "." + i);
// single marker
assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchInMulti[j], searchForMulti[i], markerStart.substring(j, j + 1),
- markerEnd.substring(j, j + 1), StringUtils.SEARCH_MODE__MRK_WS), "Test C." + j + "." + i);
+ markerEnd.substring(j, j + 1), SearchMode.__MRK_WS), "Test C." + j + "." + i);
assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchInMulti[j], searchForMulti[i], markerStart.substring(j, j + 1),
- markerEnd.substring(j, j + 1), StringUtils.SEARCH_MODE__BSESC_MRK_WS), "Test C." + j + "." + i);
+ markerEnd.substring(j, j + 1), SearchMode.__BSE_MRK_WS), "Test C." + j + "." + i);
}
}
@@ -156,12 +157,10 @@ public void testIndexOfIgnoreCase() throws Exception {
expectedIdx = new int[] { 18, 26, -1, -1, 48, 37 };
for (int i = 0; i < searchForMulti.length; i++) {
// multiple markers
- assertEquals(expectedIdx[i],
- StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS),
+ assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, SearchMode.__BSE_MRK_WS),
"Test C.4." + i);
// single marker
- assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], "'", "'", StringUtils.SEARCH_MODE__BSESC_MRK_WS),
- "Test C.5." + i);
+ assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], "'", "'", SearchMode.__BSE_MRK_WS), "Test C.5." + i);
}
searchIn = "A 'strange \\''STRONG \\`SsSTRING\\\" to be searched in";
@@ -169,12 +168,10 @@ public void testIndexOfIgnoreCase() throws Exception {
expectedIdx = new int[] { 14, 24, -1, -1, 48, 37 };
for (int i = 0; i < searchForMulti.length; i++) {
// multiple markers
- assertEquals(expectedIdx[i],
- StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, StringUtils.SEARCH_MODE__BSESC_MRK_WS),
+ assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, SearchMode.__BSE_MRK_WS),
"Test C.6." + i);
// single marker
- assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], "'", "'", StringUtils.SEARCH_MODE__BSESC_MRK_WS),
- "Test C.7." + i);
+ assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], "'", "'", SearchMode.__BSE_MRK_WS), "Test C.7." + i);
}
/*
@@ -182,122 +179,165 @@ public void testIndexOfIgnoreCase() throws Exception {
* searchMode) using combined and single search modes
*/
// basic test set
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, null, (String) null, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, null, "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", (String) null, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "bcd", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab -- abc", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab # abc", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/*/* /c", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/**/c", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/* abc */c", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(0, StringUtils.indexOfIgnoreCase(0, "abc", "abc", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(3, StringUtils.indexOfIgnoreCase(0, "abc d efg", " d ", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
+ assertThrows(IllegalArgumentException.class, "The source string must not be null.", () -> {
+ StringUtils.indexOfIgnoreCase(0, null, (String) null, markerStart, markerEnd, SearchMode.__FULL);
+ return null;
+ });
+ assertThrows(IllegalArgumentException.class, "The source string must not be null.", () -> {
+ StringUtils.indexOfIgnoreCase(0, null, "abc", markerStart, markerEnd, SearchMode.__FULL);
+ return null;
+ });
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", (String) null, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", "bcd", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab -- abc", "abc", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab # abc", "abc", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/*/* /c", "abc", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/**/c", "abc", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "ab/* abc */c", "abc", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(0, StringUtils.indexOfIgnoreCase(0, "abc", "abc", markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(3, StringUtils.indexOfIgnoreCase(0, "abc d efg", " d ", markerStart, markerEnd, SearchMode.__FULL));
// exhaustive test set
searchIn = "/* MySQL01 *//* MySQL02 */ \"MySQL03\" /* MySQL04 */-- MySQL05\n/* MySQL06 *//* MySQL07 */ 'MySQL08' /* MySQL09 */-- # MySQL10\r\n"
+ "/* MySQL11 *//* MySQL12 */ `MySQL13` /* MySQL14 */# MySQL15\r\n/* MySQL16 *//* MySQL17 */ (MySQL18) /* MySQL19 */# -- MySQL20 \n"
- + "/* MySQL21 *//* MySQL22 */ \\MySQL23--;/*! MySQL24 */ MySQL25 --";
+ + "/* MySQL21 *//* MySQL22 */ \\MySQL23--;/*!12345 MySQL24 */ /*+ MySQL25 */ MySQL26 --";
searchFor = "mYSql";
- // 1. different markers in method arguments
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, null, null, StringUtils.SEARCH_MODE__BSESC_COM_WS);
+ // D.1. different markers in method arguments
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, null, null, SearchMode.__BSE_COM_MYM_HNT_WS);
assertEquals(3, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "", "", StringUtils.SEARCH_MODE__ALL);
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "", "", SearchMode.__FULL);
assertEquals(3, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "'`(", "'`)", StringUtils.SEARCH_MODE__ALL);
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "'`(", "'`)", SearchMode.__FULL);
assertEquals(3, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "\"`(", "\"`)", StringUtils.SEARCH_MODE__ALL);
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "\"`(", "\"`)", SearchMode.__FULL);
assertEquals(8, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "\"'(", "\"')", StringUtils.SEARCH_MODE__ALL);
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "\"'(", "\"')", SearchMode.__FULL);
assertEquals(13, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "\"'`", "\"'`", StringUtils.SEARCH_MODE__ALL);
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, "`'\"", "`'\"", SearchMode.__FULL);
assertEquals(18, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- // 2a. search mode: all but skip markers
- searchMode = StringUtils.SEARCH_MODE__BSESC_COM_WS;
+ // D.2a. search mode: all but SearchMode.SKIP_BETWEEN_MARKERS
+ searchMode = SearchMode.__BSE_COM_MYM_HNT_WS;
pos = 0;
- expectedIdx = new int[] { 3, 8, 13, 18, 24, 25, -1 };
+ expectedIdx = new int[] { 3, 8, 13, 18, 23, 24, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.2a." + i);
}
- // 2b. search mode: only skip markers
+ // D.2b. search mode: only SearchMode.SKIP_BETWEEN_MARKERS
searchMode = EnumSet.of(SearchMode.SKIP_BETWEEN_MARKERS);
pos = 0;
- expectedIdx = new int[] { 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, -1 };
+ expectedIdx = new int[] { 1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.2b." + i);
}
- // 3a. search mode: all but skip line comments
- searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS,
- SearchMode.SKIP_WHITE_SPACE);
+ // D.3a. search mode: all but SearchMode.SKIP_BLOCK_COMMENTS
+ searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_LINE_COMMENTS,
+ SearchMode.SKIP_MYSQL_MARKERS, SearchMode.SKIP_HINT_BLOCKS, SearchMode.SKIP_WHITE_SPACE);
pos = 0;
- expectedIdx = new int[] { 5, 10, 15, 20, 24, 25, -1 };
+ expectedIdx = new int[] { 1, 2, 4, 6, 7, 9, 11, 12, 14, 16, 17, 19, 21, 22, 23, 24, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.3a." + i);
}
- // 3b. search mode: only skip line comments
- searchMode = EnumSet.of(SearchMode.SKIP_LINE_COMMENTS);
+ // D.3b. search mode: only SearchMode.SKIP_BLOCK_COMMENTS
+ searchMode = EnumSet.of(SearchMode.SKIP_BLOCK_COMMENTS);
pos = 0;
- expectedIdx = new int[] { 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 25, -1 };
+ expectedIdx = new int[] { 3, 5, 8, 10, 13, 15, 18, 20, 23, 24, 25, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.3b." + i);
}
- // 4a. search mode: all but skip block comments
- searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_WHITE_SPACE);
+ // D.4a. search mode: all but SearchMode.SKIP_LINE_COMMENTS
+ searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS,
+ SearchMode.SKIP_MYSQL_MARKERS, SearchMode.SKIP_HINT_BLOCKS, SearchMode.SKIP_WHITE_SPACE);
pos = 0;
- expectedIdx = new int[] { 1, 2, 4, 6, 7, 9, 11, 12, 14, 16, 17, 19, 21, 22, 24, 25, -1 };
+ expectedIdx = new int[] { 5, 10, 15, 20, 23, 24, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.4a." + i);
}
- // 4b. search mode: only skip block comments
- searchMode = EnumSet.of(SearchMode.SKIP_BLOCK_COMMENTS);
+ // D.4b. search mode: only SearchMode.SKIP_LINE_COMMENTS
+ searchMode = EnumSet.of(SearchMode.SKIP_LINE_COMMENTS);
pos = 0;
- expectedIdx = new int[] { 3, 5, 8, 10, 13, 15, 18, 20, 23, 24, 25, -1 };
+ expectedIdx = new int[] { 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.4b." + i);
}
- // 5a. search mode: all but allow backslash escape
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, markerStart, markerEnd, StringUtils.SEARCH_MODE__MRK_COM_WS);
+ // D.5a. search mode: all but SearchMode.SKIP_MYSQL_MARKERS
+ searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS,
+ SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_HINT_BLOCKS, SearchMode.SKIP_WHITE_SPACE);
+ pos = 0;
+ expectedIdx = new int[] { 23, 24, 26, -1 };
+ for (int i = 0; i < expectedIdx.length; i++, pos++) {
+ pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
+ assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.5a." + i);
+ }
+ // D.5b. search mode: only SearchMode.SKIP_MYSQL_MARKERS
+ searchMode = EnumSet.of(SearchMode.SKIP_MYSQL_MARKERS);
+ pos = 0;
+ expectedIdx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1 };
+ for (int i = 0; i < expectedIdx.length; i++, pos++) {
+ pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
+ assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.5b." + i);
+ }
+
+ // D.6a. search mode: all but SearchMode.SKIP_HINT_BLOCKS
+ searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS,
+ SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_MYSQL_MARKERS, SearchMode.SKIP_WHITE_SPACE);
+ pos = 0;
+ expectedIdx = new int[] { 23, 24, 25, 26, -1 };
+ for (int i = 0; i < expectedIdx.length; i++, pos++) {
+ pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
+ assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.6a." + i);
+ }
+ // D.6b. search mode: only SearchMode.SKIP_HINT_BLOCKS
+ searchMode = EnumSet.of(SearchMode.SKIP_HINT_BLOCKS);
+ pos = 0;
+ expectedIdx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, -1 };
+ for (int i = 0; i < expectedIdx.length; i++, pos++) {
+ pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
+ assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.6b." + i);
+ }
+
+ // D.7a. search mode: all but SearchMode.ALLOW_BACKSLASH_ESCAPE
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, searchFor, markerStart, markerEnd, SearchMode.__MRK_COM_MYM_HNT_WS);
assertEquals(23, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- // 5b. search mode: only allow backslash escape
+ // D.7b. search mode: only allow backslash escape
searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE);
pos = 0;
- expectedIdx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, -1 };
+ expectedIdx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, searchMode);
- assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.5b." + i);
+ assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.7b." + i);
}
- // 6. all together
+ // D.8. all together
pos = 0;
- expectedIdx = new int[] { 24, 25, -1 };
+ expectedIdx = new int[] { 23, 24, 26, -1 };
for (int i = 0; i < expectedIdx.length; i++, pos++) {
- pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL);
- assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.6." + i);
+ pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, SearchMode.__FULL);
+ assertEquals(expectedIdx[i], testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.8." + i);
}
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, "YourSQL", markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL);
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, "YourSQL", markerStart, markerEnd, SearchMode.__FULL);
assertEquals(-1, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- // 7. none
+ // D.9. none
pos = 0;
- for (int i = 1; i <= 25; i++, pos++) {
- pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, StringUtils.SEARCH_MODE__NONE);
- assertEquals(i, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.7." + i);
+ for (int i = 1; i <= 26; i++, pos++) {
+ pos = StringUtils.indexOfIgnoreCase(pos, searchIn, searchFor, markerStart, markerEnd, SearchMode.__NONE);
+ assertEquals(i, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos), "Test D.9." + i);
}
- pos = StringUtils.indexOfIgnoreCase(pos + 1, searchIn, searchFor, markerStart, markerEnd, StringUtils.SEARCH_MODE__NONE);
+ pos = StringUtils.indexOfIgnoreCase(pos + 1, searchIn, searchFor, markerStart, markerEnd, SearchMode.__NONE);
assertEquals(-1, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
- pos = StringUtils.indexOfIgnoreCase(0, searchIn, "YourSQL", markerStart, markerEnd, StringUtils.SEARCH_MODE__NONE);
+ pos = StringUtils.indexOfIgnoreCase(0, searchIn, "YourSQL", markerStart, markerEnd, SearchMode.__NONE);
assertEquals(-1, testIndexOfIgnoreCaseMySQLIndexMarker(searchIn, pos));
/*
@@ -377,7 +417,7 @@ public Void call() throws Exception {
for (int i = 0; i < searchForMulti.length; i++) {
assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, searchMode), "Test F.3." + i);
}
- searchMode = StringUtils.SEARCH_MODE__BSESC_COM_WS;
+ searchMode = SearchMode.__BSE_COM_MYM_HNT_WS;
expectedIdx = new int[] { 0, 5, 12, 21 };
for (int i = 0; i < searchForMulti.length; i++) {
assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, searchMode), "Test F.4." + i);
@@ -391,7 +431,7 @@ public Void call() throws Exception {
for (int i = 0; i < searchForMulti.length; i++) {
assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, searchMode), "Test F.5." + i);
}
- searchMode = StringUtils.SEARCH_MODE__BSESC_COM_WS;
+ searchMode = SearchMode.__BSE_COM_MYM_HNT_WS;
expectedIdx = new int[] { 0, 5, 12, 24 };
for (int i = 0; i < searchForMulti.length; i++) {
assertEquals(expectedIdx[i], StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti[i], markerStart, markerEnd, searchMode), "Test F.6." + i);
@@ -402,57 +442,48 @@ public Void call() throws Exception {
* searchMode) using all combined search modes
*/
// basic test set
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, null, (String[]) null, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, null, new String[] { "abc" }, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", (String[]) null, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", new String[] {}, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", new String[] { "", "" }, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc -- d", new String[] { "c", "d" }, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(0, StringUtils.indexOfIgnoreCase(0, "abc", new String[] { "abc" }, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1,
- StringUtils.indexOfIgnoreCase(0, "abc d efg h", new String[] { " d ", " efg" }, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(3, StringUtils.indexOfIgnoreCase(0, "abc d efg h", new String[] { " d ", "efg" }, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
+ assertThrows(IllegalArgumentException.class, "The source string must not be null.", () -> {
+ StringUtils.indexOfIgnoreCase(0, null, (String[]) null, markerStart, markerEnd, SearchMode.__FULL);
+ return null;
+ });
+ assertThrows(IllegalArgumentException.class, "The source string must not be null.", () -> {
+ StringUtils.indexOfIgnoreCase(0, null, new String[] { "abc" }, markerStart, markerEnd, SearchMode.__FULL);
+ return null;
+ });
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", (String[]) null, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", new String[] {}, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc", new String[] { "", "" }, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc -- d", new String[] { "c", "d" }, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(0, StringUtils.indexOfIgnoreCase(0, "abc", new String[] { "abc" }, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "abc d efg h", new String[] { " d ", " efg" }, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(3, StringUtils.indexOfIgnoreCase(0, "abc d efg h", new String[] { " d ", "efg" }, markerStart, markerEnd, SearchMode.__FULL));
// exhaustive test set
searchForMulti = new String[] { "ONE", "two", "ThrEE" };
// 1. simple strings
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "onetwothee", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "one one one one two", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(11, StringUtils.indexOfIgnoreCase(0, "onetwothee one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(20,
- StringUtils.indexOfIgnoreCase(0, "/* one two three */ one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "onetwothee", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "one one one one two", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(11, StringUtils.indexOfIgnoreCase(0, "onetwothee one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(20, StringUtils.indexOfIgnoreCase(0, "/* one two three */ one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
assertEquals(38, StringUtils.indexOfIgnoreCase(0, "/* one two three *//* one two three */one two three", searchForMulti, markerStart, markerEnd,
- StringUtils.SEARCH_MODE__ALL));
- assertEquals(7,
- StringUtils.indexOfIgnoreCase(0, "/*one*/one/*two*/two/*three*/three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(0,
- StringUtils.indexOfIgnoreCase(0, "one/*one*/two/*two*/three/*three*/", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(16,
- StringUtils.indexOfIgnoreCase(0, "# one two three\none two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(17,
- StringUtils.indexOfIgnoreCase(0, "-- one two three\none two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(22,
- StringUtils.indexOfIgnoreCase(0, "/* one two three */--;one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(4,
- StringUtils.indexOfIgnoreCase(0, "/*! one two three */--;one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(9, StringUtils.indexOfIgnoreCase(0, "/*!50616 one two three */--;one two three", searchForMulti, markerStart, markerEnd,
- StringUtils.SEARCH_MODE__ALL));
- assertEquals(16,
- StringUtils.indexOfIgnoreCase(0, "\"one two three\" one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(16,
- StringUtils.indexOfIgnoreCase(0, "'one two three' one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(16,
- StringUtils.indexOfIgnoreCase(0, "`one two three` one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
- assertEquals(16,
- StringUtils.indexOfIgnoreCase(0, "(one two three) one two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
-
- assertEquals(3, StringUtils.indexOfIgnoreCase(0, "/* one two three */ one two three", searchForMulti, markerStart, markerEnd,
- StringUtils.SEARCH_MODE__NONE));
- assertEquals(2,
- StringUtils.indexOfIgnoreCase(0, "# one two three\none two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__NONE));
- assertEquals(3,
- StringUtils.indexOfIgnoreCase(0, "-- one two three\none two three", searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__NONE));
+ SearchMode.__FULL));
+ assertEquals(7, StringUtils.indexOfIgnoreCase(0, "/*one*/one/*two*/two/*three*/three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(0, StringUtils.indexOfIgnoreCase(0, "one/*one*/two/*two*/three/*three*/", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(16, StringUtils.indexOfIgnoreCase(0, "# one two three\none two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(17, StringUtils.indexOfIgnoreCase(0, "-- one two three\none two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(22, StringUtils.indexOfIgnoreCase(0, "/* one two three */--;one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(4, StringUtils.indexOfIgnoreCase(0, "/*! one two three */--;one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(9,
+ StringUtils.indexOfIgnoreCase(0, "/*!50616 one two three */--;one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(16, StringUtils.indexOfIgnoreCase(0, "\"one two three\" one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(16, StringUtils.indexOfIgnoreCase(0, "'one two three' one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(16, StringUtils.indexOfIgnoreCase(0, "`one two three` one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+ assertEquals(16, StringUtils.indexOfIgnoreCase(0, "(one two three) one two three", searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
+
+ assertEquals(3, StringUtils.indexOfIgnoreCase(0, "/* one two three */ one two three", searchForMulti, markerStart, markerEnd, SearchMode.__NONE));
+ assertEquals(2, StringUtils.indexOfIgnoreCase(0, "# one two three\none two three", searchForMulti, markerStart, markerEnd, SearchMode.__NONE));
+ assertEquals(3, StringUtils.indexOfIgnoreCase(0, "-- one two three\none two three", searchForMulti, markerStart, markerEnd, SearchMode.__NONE));
// 2. complex string
searchIn = "/* one two three *//* one two three */ one 'two' three -- \"one/* one */two three\" one owt three\n"
@@ -461,11 +492,11 @@ public Void call() throws Exception {
printRuler(searchIn);
// 2.1. skip all
- assertEquals(159, StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__ALL));
+ assertEquals(159, StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti, markerStart, markerEnd, SearchMode.__FULL));
// 2.2. search within block comments
searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_WHITE_SPACE);
assertEquals(3, StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti, markerStart, markerEnd, searchMode));
- assertEquals(3, StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti, markerStart, markerEnd, StringUtils.SEARCH_MODE__NONE));
+ assertEquals(3, StringUtils.indexOfIgnoreCase(0, searchIn, searchForMulti, markerStart, markerEnd, SearchMode.__NONE));
// 2.3. search within line comments and unidentified markers
searchMode = EnumSet.of(SearchMode.ALLOW_BACKSLASH_ESCAPE, SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS,
SearchMode.SKIP_WHITE_SPACE);
@@ -1358,4 +1389,70 @@ public void testQuoteUnquoteBytes() throws Exception {
assertEquals(origBytes[i], unquotedBytes[i]);
}
}
+
+ @Test
+ public void testStringUtils001() throws Exception {
+ char[] cdata = new char[26];
+ byte[] bdata = new byte[26];
+ String s1 = "String Consist of some small Sample Data";
+ for (int i = 0; i < 26; i++) {
+ cdata[i] = (char) ('A' + i);
+ }
+
+ byte[] bdata3 = new byte[26];
+ for (int i = 0; i < 26; i++) {
+ bdata3[i] = (byte) ('a' + i % 6);
+ }
+
+ System.out.print("\n StringUtils.escapeQuote(XabXcX) :" + StringUtils.escapeQuote("XXabcX", "X"));
+ System.out.print("\n StringUtils.escapeQuote('ab'c') :" + StringUtils.escapeQuote("'ab'c'", "'"));
+ System.out.print("\n StringUtils.escapeQuote('select \\1\\, \\6\\') :" + StringUtils.escapeQuote("select \\1\\, \\6\\", "\\"));
+
+ assertEquals("''abc", StringUtils.escapeQuote("''abc'", "'"), "escapeQuote() returns Wrong result");
+ assertEquals('R', StringUtils.firstNonWsCharUc(" \t Raj"), "firstNonWsCharUc() returns Wrong result");
+ assertEquals("select \\\\1\\\\, \\\\6\\\\", StringUtils.escapeQuote("select \\1\\, \\6\\", "\\"), "escapeQuote() returns Wrong result");
+ String s2 = null;
+ assertEquals(null, StringUtils.escapeQuote(s2, "'"), "escapeQuote() returns Wrong result");
+ bdata = StringUtils.getBytes(cdata, 5, 5);
+
+ System.out.print("\n indexOf(bdata2,'F') (0):" + StringUtils.indexOf(bdata, 'F'));
+ System.out.print("\n indexOf(bdata2,'I') (3):" + StringUtils.indexOf(bdata, 'I'));
+ System.out.print("\n isValidIdChar('+') (false) : " + StringUtils.isValidIdChar('+'));
+ System.out.print("\n isValidIdChar('X')(true) : " + StringUtils.isValidIdChar('X'));
+ System.out.print("\n lastIndexOf(bdata3,'d')(21) :" + StringUtils.lastIndexOf(bdata3, 'd'));
+ System.out.print("\n indexOf(bdata3,'d') (3):" + StringUtils.indexOf(bdata3, 'd'));
+ System.out.print("\n wildCompareIgnoreCase(s1,'some%mal') (false):" + StringUtils.wildCompareIgnoreCase(s1, "some%mal"));
+ System.out.print("\n wildCompareIgnoreCase(s1,'some_s_al_') (false):" + StringUtils.wildCompareIgnoreCase(s1, "some_s_al_"));
+ System.out.print("\n wildCompareIgnoreCase(s1,'some') (false):" + StringUtils.wildCompareIgnoreCase(s1, "some"));
+ System.out.print("\n wildCompareIgnoreCase(s1,'S_%s_%S_%Da%'):" + StringUtils.wildCompareIgnoreCase(s1, "S_%s_%S_%Da%"));
+ System.out.print("\n wildCompareIgnoreCase(s1,'S_r_n_ C_n_i_t%'):" + StringUtils.wildCompareIgnoreCase(s1, "S_r_n_ C_n_i_t%"));
+ assertEquals(0, StringUtils.indexOf(bdata, 'F'), "indexOf() returns Wrong result");
+ assertEquals(false, StringUtils.isValidIdChar('+'), "isValidIdChar() returns Wrong result");
+ assertEquals(true, StringUtils.isValidIdChar('X'), "isValidIdChar() returns Wrong result");
+ assertEquals(21, StringUtils.lastIndexOf(bdata3, 'd'), "lastIndexOf() returns Wrong result");
+ assertEquals(3, StringUtils.indexOf(bdata3, 'd'), "indexOf() returns Wrong result");
+
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, "some"), "wildCompareIgnoreCase() returns Wrong result");
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, "small"), "wildCompareIgnoreCase() returns Wrong result");
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, "Data"), "wildCompareIgnoreCase() returns Wrong result");
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, "amp"), "wildCompareIgnoreCase() returns Wrong result");
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, " "), "wildCompareIgnoreCase() returns Wrong result");
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, "some_s_al_"), "wildCompareIgnoreCase() returns Wrong result");
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, "some%mal"), "wildCompareIgnoreCase() returns Wrong result");
+
+ assertFalse(StringUtils.wildCompareIgnoreCase(s1, "some_s_al_"), "wildCompareIgnoreCase() returns Wrong result");
+ assertTrue(StringUtils.wildCompareIgnoreCase(s1, "S_r_n_ C_n_i_t%"), "wildCompareIgnoreCase() returns Wrong result");
+
+ System.out.print("\n firstNonWsCharUc(' \t Raj') : " + StringUtils.firstNonWsCharUc(" \t Raj"));
+ System.out.print("\n escapeQuote('select '1', '6'') : " + StringUtils.escapeQuote("select '1', '6'", "'"));
+ }
+
+ @Test
+ public void testStripComments() throws Exception {
+ String testString = "-- 1st comment\nthis\nis/* 2nd comment */not # 3rd \"comment\"\n-- 4th comment\r\n /* 5th comment */a 'comment'"
+ + "--neither this! nor '# this is a comment'";
+ String expected = "this\nis not a 'comment'--neither this! nor '# this is a comment'";
+
+ assertEquals(expected, StringUtils.stripCommentsAndHints(testString, "\"'", "\"'", true));
+ }
}
diff --git a/src/test/java/com/mysql/cj/xdevapi/ExprParserTest.java b/src/test/java/com/mysql/cj/xdevapi/ExprParserTest.java
index d935f1cbd..a7e341c90 100644
--- a/src/test/java/com/mysql/cj/xdevapi/ExprParserTest.java
+++ b/src/test/java/com/mysql/cj/xdevapi/ExprParserTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -31,8 +31,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
import java.util.Arrays;
import java.util.Iterator;
@@ -62,13 +62,10 @@ public class ExprParserTest {
* @param s
*/
private void checkBadParse(String s) {
- try {
+ assertThrows(WrongArgumentException.class, () -> {
Expr e = new ExprParser(s).parse();
System.err.println("Parsed as: " + e);
- fail("Expected exception while parsing: '" + s + "'");
- } catch (WrongArgumentException ex) {
- // expected
- }
+ }, "Expected exception while parsing: '" + s + "'");
}
@Test
diff --git a/src/test/java/com/mysql/cj/xdevapi/JsonDocTest.java b/src/test/java/com/mysql/cj/xdevapi/JsonDocTest.java
index 2390d2e0b..9783da79c 100644
--- a/src/test/java/com/mysql/cj/xdevapi/JsonDocTest.java
+++ b/src/test/java/com/mysql/cj/xdevapi/JsonDocTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -719,10 +719,8 @@ protected static EX assertThrows(Class throwable, Cal
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.");
- }
-
+ assertTrue(throwable.isAssignableFrom(t.getClass()),
+ "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() + "'.");
@@ -735,14 +733,9 @@ protected static EX assertThrows(Class throwable, Str
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.");
- }
-
- if (!t.getMessage().matches(msgMatchesRegex)) {
- fail("The error message [" + t.getMessage() + "] was expected to match [" + msgMatchesRegex + "].");
- }
-
+ assertTrue(throwable.isAssignableFrom(t.getClass()),
+ "Expected exception of type '" + throwable.getName() + "' but instead a exception of type '" + t.getClass().getName() + "' was thrown.");
+ assertTrue(t.getMessage().matches(msgMatchesRegex), "The error message [" + t.getMessage() + "] was expected to match [" + msgMatchesRegex + "].");
return throwable.cast(t);
}
fail("Expected exception of type '" + throwable.getName() + "'.");
diff --git a/src/test/java/testsuite/BaseTestCase.java b/src/test/java/testsuite/BaseTestCase.java
index eb81c7c22..4dc2a943b 100644
--- a/src/test/java/testsuite/BaseTestCase.java
+++ b/src/test/java/testsuite/BaseTestCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -31,6 +31,7 @@
import static com.mysql.cj.util.StringUtils.isNullOrEmpty;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -70,6 +71,7 @@
import com.mysql.cj.conf.ConnectionUrlParser;
import com.mysql.cj.conf.HostInfo;
import com.mysql.cj.conf.PropertyDefinitions;
+import com.mysql.cj.conf.PropertyDefinitions.SslMode;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.jdbc.JdbcConnection;
import com.mysql.cj.jdbc.NonRegisteringDriver;
@@ -81,14 +83,6 @@
* Base class for all test cases. Creates connections, statements, etc. and closes them.
*/
public abstract class BaseTestCase {
- // next variables disable some tests
- protected boolean DISABLED_testBug15121 = true; // TODO needs to be fixed on server
- protected boolean DISABLED_testBug7033 = true; // TODO disabled for unknown reason
- protected boolean DISABLED_testBug2654 = true; // TODO check if it's still a server-level bug
- protected boolean DISABLED_testBug5136 = true; // TODO disabled for unknown reason
- protected boolean DISABLED_testBug65503 = true; // TODO disabled for unknown reason
- protected boolean DISABLED_testContention = true; // TODO disabled for unknown reason
- protected boolean DISABLED_testBug3620new = true; // TODO this test is working in c/J 5.1 but fails here; disabled for later analysis
/**
* JDBC URL, initialized from com.mysql.cj.testsuite.url system property, or defaults to jdbc:mysql:///test and its connection URL.
@@ -96,12 +90,7 @@ public abstract class BaseTestCase {
public static String dbUrl = "jdbc:mysql:///test";
public static String timeZoneFreeDbUrl = "jdbc:mysql:///test";
protected static ConnectionUrl mainConnectionUrl = null;
-
- /**
- * JDBC URL, initialized from com.mysql.cj.testsuite.url.openssl system property and its connection URL
- */
- protected static String sha256Url = null;
- protected static ConnectionUrl sha256ConnectionUrl = null;
+ protected boolean isOpenSSL = false;
/** Instance counter */
private static int instanceCount = 1;
@@ -109,8 +98,6 @@ public abstract class BaseTestCase {
/** Connection to server, initialized in setUp() Cleaned up in tearDown(). */
protected Connection conn = null;
- protected Connection sha256Conn = null;
-
/** Server version `this.conn' is connected to. */
protected ServerVersion serverVersion;
@@ -129,7 +116,7 @@ public abstract class BaseTestCase {
/**
* Default catalog.
*/
- protected final String dbName;
+ protected String dbName;
/**
* PreparedStatement to be used in tests, not initialized. Cleaned up in
@@ -142,16 +129,12 @@ public abstract class BaseTestCase {
*/
protected ResultSet rs = null;
- protected ResultSet sha256Rs = null;
-
/**
* Statement to be used in tests, initialized in setUp(). Cleaned up in
* tearDown().
*/
protected Statement stmt = null;
- protected Statement sha256Stmt = null;
-
private boolean isOnCSFS = true;
/**
@@ -163,19 +146,32 @@ public BaseTestCase() {
String newDbUrl = System.getProperty(PropertyDefinitions.SYSP_testsuite_url);
if ((newDbUrl != null) && (newDbUrl.trim().length() != 0)) {
- dbUrl = newDbUrl;
+ dbUrl = sanitizeDbName(newDbUrl);
}
- timeZoneFreeDbUrl = dbUrl.replaceAll(PropertyKey.connectionTimeZone.getKeyName() + "=", PropertyKey.connectionTimeZone.getKeyName() + "VOID=")
- .replaceAll("serverTimezone=", "serverTimezoneVOID=");
mainConnectionUrl = ConnectionUrl.getConnectionUrlInstance(dbUrl, null);
this.dbName = mainConnectionUrl.getDatabase();
- String defaultSha256Url = System.getProperty(PropertyDefinitions.SYSP_testsuite_url_openssl);
+ timeZoneFreeDbUrl = dbUrl.replaceAll(PropertyKey.connectionTimeZone.getKeyName() + "=", PropertyKey.connectionTimeZone.getKeyName() + "VOID=")
+ .replaceAll("serverTimezone=", "serverTimezoneVOID=");
+ }
- if ((defaultSha256Url != null) && (defaultSha256Url.trim().length() != 0)) {
- sha256Url = defaultSha256Url;
- sha256ConnectionUrl = ConnectionUrl.getConnectionUrlInstance(sha256Url, null);
+ private String sanitizeDbName(String url) {
+ ConnectionUrl parsedUrl = ConnectionUrl.getConnectionUrlInstance(url, null);
+ if (StringUtils.isNullOrEmpty(parsedUrl.getDatabase())) {
+ List splitUp = StringUtils.split(url, "\\?", true);
+ StringBuilder value = new StringBuilder();
+ for (int i = 0; i < splitUp.size(); i++) {
+ value.append(splitUp.get(i));
+ if (i == 0) {
+ if (!splitUp.get(i).endsWith("/")) {
+ value.append("/");
+ }
+ value.append("cjtest_8_0?");
+ }
+ }
+ url = value.toString();
}
+ return url;
}
protected void createSchemaObject(String objectType, String objectName, String columnsAndOtherStuff) throws SQLException {
@@ -334,19 +330,6 @@ protected void dropSchemaObject(Statement st, String objectType, String objectNa
}
}
- protected Connection getAdminConnection() throws SQLException {
- return getAdminConnectionWithProps(new Properties());
- }
-
- protected Connection getAdminConnectionWithProps(Properties props) throws SQLException {
- String adminUrl = System.getProperty(PropertyDefinitions.SYSP_testsuite_url_admin);
-
- if (adminUrl != null) {
- return DriverManager.getConnection(adminUrl, props);
- }
- return null;
- }
-
public Connection getConnectionWithProps(String propsList) throws SQLException {
return getConnectionWithProps(dbUrl, propsList);
}
@@ -397,16 +380,10 @@ protected Connection getConnectionWithProps(String url, Properties props) throws
}
protected Connection getNewConnection() throws SQLException {
- return DriverManager.getConnection(dbUrl);
- }
-
- protected Connection getNewSha256Connection() throws SQLException {
- if (sha256Url != null) {
- Properties props = new Properties();
- props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- return DriverManager.getConnection(sha256Url, props);
- }
- return null;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ return DriverManager.getConnection(dbUrl, props);
}
/**
@@ -599,10 +576,6 @@ protected Object getSingleValueWithQuery(String query) throws SQLException {
return getSingleIndexedValueWithQuery(1, query);
}
- protected boolean isAdminConnectionConfigured() {
- return System.getProperty(PropertyDefinitions.SYSP_testsuite_url_admin) != null;
- }
-
protected boolean isServerRunningOnWindows() throws SQLException {
return (getMysqlVariable("datadir").indexOf('\\') != -1);
}
@@ -645,14 +618,9 @@ protected final boolean runLongTests() {
*/
protected boolean isSysPropDefined(String propName) {
String prop = System.getProperty(propName);
-
return (prop != null) && (prop.length() > 0);
}
- protected boolean runMultiHostTests() {
- return !isSysPropDefined(PropertyDefinitions.SYSP_testsuite_disable_multihost_tests);
- }
-
/**
* Creates resources used by all tests.
*
@@ -670,12 +638,14 @@ public void setUpBase(TestInfo testInfo) throws Exception {
this.createdObjects = new ArrayList<>();
Properties props = new Properties();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false"); // testsuite is built upon non-SSL default connection
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name()); // testsuite is built upon non-SSL default connection
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.createDatabaseIfNotExist.getKeyName(), "true");
+ if (StringUtils.isNullOrEmpty(mainConnectionUrl.getDatabase())) {
+ props.setProperty(PropertyKey.DBNAME.getKeyName(), this.dbName);
+ }
this.conn = DriverManager.getConnection(dbUrl, props);
- this.sha256Conn = sha256Url == null ? null : DriverManager.getConnection(sha256Url, props);
-
this.serverVersion = ((JdbcConnection) this.conn).getServerVersion();
this.stmt = this.conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
@@ -685,6 +655,25 @@ public void setUpBase(TestInfo testInfo) throws Exception {
this.rs = this.stmt.executeQuery("SELECT VERSION()");
this.rs.next();
logDebug("Connected to " + this.rs.getString(1));
+ this.rs.close();
+ this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'auto_generate_certs'");
+ if (this.rs.next()) {
+ this.isOpenSSL = true;
+ }
+
+ // ensure max_connections value is enough to run tests
+ this.rs.close();
+ this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'max_connections'");
+ this.rs.next();
+ int maxConnections = this.rs.getInt(2);
+
+ this.rs = this.stmt.executeQuery("show status like 'threads_connected'");
+ this.rs.next();
+ int usedConnections = this.rs.getInt(2);
+
+ if (maxConnections - usedConnections < 200) {
+ this.stmt.executeUpdate("SET GLOBAL max_connections=" + (maxConnections + 200));
+ }
} else {
logDebug("Connected to " + this.conn.getMetaData().getDatabaseProductName() + " / " + this.conn.getMetaData().getDatabaseProductVersion());
}
@@ -696,26 +685,6 @@ public void setUpBase(TestInfo testInfo) throws Exception {
}
this.isOnCSFS = !this.conn.getMetaData().storesLowerCaseIdentifiers();
-
- if (this.sha256Conn != null) {
- this.sha256Stmt = this.sha256Conn.createStatement();
-
- try {
- if (sha256Url.indexOf("mysql") != -1) {
- this.sha256Rs = this.sha256Stmt.executeQuery("SELECT VERSION()");
- this.sha256Rs.next();
- logDebug("Connected to " + this.sha256Rs.getString(1));
- } else {
- logDebug("Connected to " + this.sha256Conn.getMetaData().getDatabaseProductName() + " / "
- + this.sha256Conn.getMetaData().getDatabaseProductVersion());
- }
- } finally {
- if (this.sha256Rs != null) {
- this.sha256Rs.close();
- this.sha256Rs = null;
- }
- }
- }
}
/**
@@ -732,22 +701,8 @@ public void tearDownBase() throws Exception {
}
}
- if (this.sha256Rs != null) {
- try {
- this.sha256Rs.close();
- } catch (SQLException SQLE) {
- }
- }
-
if (System.getProperty(PropertyDefinitions.SYSP_testsuite_retainArtifacts) == null) {
- Statement st = this.conn == null || this.conn.isClosed() ? getNewConnection().createStatement() : this.conn.createStatement();
- Statement sha256st;
- if (this.sha256Conn == null || this.sha256Conn.isClosed()) {
- Connection c = getNewSha256Connection();
- sha256st = c == null ? null : c.createStatement();
- } else {
- sha256st = this.sha256Conn.createStatement();
- }
+ Statement st = (this.conn == null || this.conn.isClosed() ? getNewConnection() : this.conn).createStatement();
for (int i = 0; i < this.createdObjects.size(); i++) {
String[] objectInfo = this.createdObjects.get(i);
@@ -756,16 +711,8 @@ public void tearDownBase() throws Exception {
dropSchemaObject(st, objectInfo[0], objectInfo[1]);
} catch (SQLException SQLE) {
}
-
- try {
- dropSchemaObject(sha256st, objectInfo[0], objectInfo[1]);
- } catch (SQLException SQLE) {
- }
}
st.close();
- if (sha256st != null) {
- sha256st.close();
- }
}
if (this.stmt != null) {
@@ -775,13 +722,6 @@ public void tearDownBase() throws Exception {
}
}
- if (this.sha256Stmt != null) {
- try {
- this.sha256Stmt.close();
- } catch (SQLException SQLE) {
- }
- }
-
if (this.pstmt != null) {
try {
this.pstmt.close();
@@ -795,13 +735,6 @@ public void tearDownBase() throws Exception {
} catch (SQLException SQLE) {
}
}
-
- if (this.sha256Conn != null) {
- try {
- this.sha256Conn.close();
- } catch (SQLException SQLE) {
- }
- }
}
/**
@@ -1009,15 +942,10 @@ protected static EX assertThrows(String message, Class 0;
+ }
+
+ protected boolean supportsLoadLocalInfile(Statement st) throws Exception {
+ ResultSet rs1 = st.executeQuery("SHOW VARIABLES LIKE 'local_infile'");
+ return rs1.next() && "ON".equalsIgnoreCase(rs1.getString(2));
+ }
+
+ protected boolean supportsTestCertificates(Statement st) throws Exception {
+ ResultSet rs1 = st.executeQuery("SHOW VARIABLES LIKE 'ssl_ca'");
+ return rs1.next() && rs1.getString(2).contains("ssl-test-certs");
+ }
+
+ protected boolean supportsTestSha256PasswordKeys(Statement st) throws Exception {
+ ResultSet rs1 = st.executeQuery("SHOW VARIABLES LIKE 'sha256_password_public_key_path'");
+ return rs1.next() && rs1.getString(2).contains("ssl-test-certs");
+ }
+
+ protected boolean supportsTestCachingSha2PasswordKeys(Statement st) throws Exception {
+ ResultSet rs1 = st.executeQuery("SHOW VARIABLES LIKE 'caching_sha2_password_private_key_path'");
+ return rs1.next() && rs1.getString(2).contains("ssl-test-certs");
+ }
+
+ protected boolean supportsTLSv1_2(ServerVersion version) throws Exception {
+ return version.meetsMinimum(new ServerVersion(5, 7, 28))
+ || version.meetsMinimum(new ServerVersion(5, 6, 46)) && !version.meetsMinimum(new ServerVersion(5, 7, 0))
+ || version.meetsMinimum(new ServerVersion(5, 6, 0)) && Util.isEnterpriseEdition(version.toString());
+
+ }
+
+ protected void assertSessionStatusEquals(Statement st, String statusVariable, String expected) throws Exception {
+ ResultSet rs1 = st.executeQuery("SHOW SESSION STATUS LIKE '" + statusVariable + "'");
+ assertTrue(rs1.next());
+ assertEquals(expected, rs1.getString(2));
+ }
+
}
diff --git a/src/test/java/testsuite/InjectedSocketFactory.java b/src/test/java/testsuite/InjectedSocketFactory.java
index 3b6459844..bbab2f5e3 100644
--- a/src/test/java/testsuite/InjectedSocketFactory.java
+++ b/src/test/java/testsuite/InjectedSocketFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2020, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -29,7 +29,7 @@
package testsuite;
-import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import java.io.Closeable;
import java.io.IOException;
@@ -363,9 +363,7 @@ public int read(byte[] b, int off, int len) throws IOException {
return readCount;
} catch (SocketTimeoutException e) {
this.loopCount++;
- if (this.loopCount > 10) {
- fail("Probable infinite loop at MySQLIO.clearInputStream().");
- }
+ assertFalse(this.loopCount > 10, "Probable infinite loop at MySQLIO.clearInputStream().");
return -1;
}
}
diff --git a/src/test/java/testsuite/perf/RetrievalPerfTest.java b/src/test/java/testsuite/perf/RetrievalPerfTest.java
index 88ab23c0f..3c11fdcad 100644
--- a/src/test/java/testsuite/perf/RetrievalPerfTest.java
+++ b/src/test/java/testsuite/perf/RetrievalPerfTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -30,6 +30,7 @@
package testsuite.perf;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -66,9 +67,9 @@ public void setUp() throws Exception {
*/
@Test
public void testRetrievalCached() throws Exception {
- if (!((MysqlConnection) this.conn).getSession().getServerSession().isQueryCacheEnabled()) {
- return;
- }
+ assumeTrue(((MysqlConnection) this.conn).getSession().getServerSession().isQueryCacheEnabled(),
+ "This test requires the server with enabled query cache.");
+
this.stmt.executeUpdate("SET QUERY_CACHE_TYPE = DEMAND");
double fullBegin = System.currentTimeMillis();
diff --git a/src/test/java/testsuite/regression/BlobRegressionTest.java b/src/test/java/testsuite/regression/BlobRegressionTest.java
index cbead9eab..e0fc0c6dc 100644
--- a/src/test/java/testsuite/regression/BlobRegressionTest.java
+++ b/src/test/java/testsuite/regression/BlobRegressionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -32,7 +32,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -50,6 +50,7 @@
import org.junit.jupiter.api.Test;
+import com.mysql.cj.conf.PropertyDefinitions.SslMode;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.util.StringUtils;
@@ -107,18 +108,44 @@ public void testBug2670() throws Exception {
*/
@Test
public void testUpdateLongBlobGT16M() throws Exception {
- byte[] blobData = new byte[18 * 1024 * 1024]; // 18M blob
-
- createTable("testUpdateLongBlob", "(blobField LONGBLOB)");
- this.stmt.executeUpdate("INSERT INTO testUpdateLongBlob (blobField) VALUES (NULL)");
+ this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'max_allowed_packet'");
+ this.rs.next();
+ long len = 4 + 1024 * 1024 * 36 + "UPDATE testUpdateLongBlob SET blobField=".length();
+ long defaultMaxAllowedPacket = this.rs.getInt(2);
+ boolean changeMaxAllowedPacket = defaultMaxAllowedPacket < len;
- this.pstmt = this.conn.prepareStatement("UPDATE testUpdateLongBlob SET blobField=?");
- this.pstmt.setBytes(1, blobData);
+ Connection con1 = null;
+ Connection con2 = null;
try {
- this.pstmt.executeUpdate();
- } catch (SQLException sqlEx) {
- if (sqlEx.getMessage().indexOf("max_allowed_packet") != -1) {
- fail("You need to increase max_allowed_packet to at least 18M before running this test!");
+ if (changeMaxAllowedPacket) {
+ this.stmt.executeUpdate("SET GLOBAL max_allowed_packet=" + 1024 * 1024 * 37);
+ }
+ byte[] blobData = new byte[18 * 1024 * 1024]; // 18M blob
+
+ createTable("testUpdateLongBlob", "(blobField LONGBLOB)");
+ this.stmt.executeUpdate("INSERT INTO testUpdateLongBlob (blobField) VALUES (NULL)");
+
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ con1 = getConnectionWithProps(props);
+ this.pstmt = con1.prepareStatement("UPDATE testUpdateLongBlob SET blobField=?");
+ this.pstmt.setBytes(1, blobData);
+ try {
+ this.pstmt.executeUpdate();
+ } catch (SQLException sqlEx) {
+ assertTrue(sqlEx.getMessage().indexOf("max_allowed_packet") == -1,
+ "You need to increase max_allowed_packet to at least 18M before running this test!");
+ }
+ } finally {
+ if (changeMaxAllowedPacket) {
+ this.stmt.executeUpdate("SET GLOBAL max_allowed_packet=" + defaultMaxAllowedPacket);
+ }
+ if (con1 != null) {
+ con1.close();
+ }
+ if (con2 != null) {
+ con2.close();
}
}
}
@@ -202,6 +229,8 @@ public void testBug8096() throws Exception {
int dataSize = 256;
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.emulateLocators.getKeyName(), "true");
Connection locatorConn = getConnectionWithProps(props);
@@ -406,25 +435,60 @@ public Void call() throws Exception {
@Test
public void testBug23535571() throws Exception {
+ this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'max_allowed_packet'");
+ this.rs.next();
+ long len = 4 + 1024 * 1024 * 36 + "UPDATE testBug23535571 SET blobField=".length();
+ long defaultMaxAllowedPacket = this.rs.getInt(2);
+ boolean changeMaxAllowedPacket = defaultMaxAllowedPacket < len;
+
+ if (!versionMeetsMinimum(5, 7)) {
+ this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'innodb_log_file_size'");
+ this.rs.next();
+ long defaultInnodbLogFileSize = this.rs.getInt(2);
+ assumeFalse(defaultInnodbLogFileSize < 1024 * 1024 * 36 * 10, "This test requires innodb_log_file_size > " + (1024 * 1024 * 36 * 10));
+ }
+
createTable("testBug23535571", "(blobField LONGBLOB)");
this.stmt.executeUpdate("INSERT INTO testBug23535571 (blobField) VALUES (NULL)");
- // Insert 1 record with 18M data
- byte[] blobData = new byte[18 * 1024 * 1024];
- this.pstmt = this.conn.prepareStatement("UPDATE testBug23535571 SET blobField=?");
- this.pstmt.setBytes(1, blobData);
- this.pstmt.executeUpdate();
+ Connection con1 = null;
+ Connection con2 = null;
+ try {
+ if (changeMaxAllowedPacket) {
+ this.stmt.executeUpdate("SET GLOBAL max_allowed_packet=" + 1024 * 1024 * 37);
+ }
- Properties props = new Properties();
- props.setProperty(PropertyKey.enablePacketDebug.getKeyName(), "true");
- Connection con = getConnectionWithProps(props);
-
- for (int i = 0; i < 100; i++) {
- this.pstmt = con.prepareStatement("select * from testBug23535571");
- this.rs = this.pstmt.executeQuery();
- this.rs.close();
- this.pstmt.close();
- Thread.sleep(100);
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ con1 = getConnectionWithProps(props);
+
+ // Insert 1 record with 18M data
+ byte[] blobData = new byte[18 * 1024 * 1024];
+ this.pstmt = con1.prepareStatement("UPDATE testBug23535571 SET blobField=?");
+ this.pstmt.setBytes(1, blobData);
+ this.pstmt.executeUpdate();
+
+ props.setProperty(PropertyKey.enablePacketDebug.getKeyName(), "true");
+ con2 = getConnectionWithProps(props);
+
+ for (int i = 0; i < 100; i++) {
+ this.pstmt = con2.prepareStatement("select * from testBug23535571");
+ this.rs = this.pstmt.executeQuery();
+ this.rs.close();
+ this.pstmt.close();
+ Thread.sleep(100);
+ }
+ } finally {
+ if (changeMaxAllowedPacket) {
+ this.stmt.executeUpdate("SET GLOBAL max_allowed_packet=" + defaultMaxAllowedPacket);
+ }
+ if (con1 != null) {
+ con1.close();
+ }
+ if (con2 != null) {
+ con2.close();
+ }
}
}
@@ -440,6 +504,8 @@ public void testBug95210() throws Exception {
this.stmt.executeUpdate("INSERT INTO testBug95210 (ID, DATA) VALUES (1, '111')");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name()); // testsuite is built upon non-SSL default connection
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.emulateLocators.getKeyName(), "true");
Connection locatorConn = getSourceReplicaReplicationConnection(props);
diff --git a/src/test/java/testsuite/regression/CachedRowsetTest.java b/src/test/java/testsuite/regression/CachedRowsetTest.java
index 1bce398b7..1767ab44e 100644
--- a/src/test/java/testsuite/regression/CachedRowsetTest.java
+++ b/src/test/java/testsuite/regression/CachedRowsetTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -32,6 +32,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
import java.lang.reflect.Method;
import java.sql.ResultSet;
@@ -54,13 +55,12 @@ public class CachedRowsetTest extends BaseTestCase {
@Test
public void testBug5188() throws Exception {
String implClass = "com.sun.rowset.CachedRowSetImpl";
- Class> c;
+ Class> c = null;
Method populate;
try {
c = Class.forName(implClass);
} catch (ClassNotFoundException e) {
- System.out.println("skipping testBug5188. Requires: " + implClass);
- return;
+ assumeFalse(true, "Requires: " + implClass);
}
populate = c.getMethod("populate", new Class>[] { ResultSet.class });
diff --git a/src/test/java/testsuite/regression/CallableStatementRegressionTest.java b/src/test/java/testsuite/regression/CallableStatementRegressionTest.java
index 7d4d59ace..519dc26aa 100644
--- a/src/test/java/testsuite/regression/CallableStatementRegressionTest.java
+++ b/src/test/java/testsuite/regression/CallableStatementRegressionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2002, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -54,6 +54,7 @@
import org.junit.jupiter.api.Test;
import com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm;
+import com.mysql.cj.conf.PropertyDefinitions.SslMode;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.exceptions.MysqlErrorNumbers;
import com.mysql.cj.jdbc.JdbcConnection;
@@ -88,7 +89,11 @@ public void testBug3539() throws Exception {
public void testBug3540() throws Exception {
createProcedure("testBug3540", "(x int, out y int)\nBEGIN\nSELECT 1;end\n");
- Connection con = getConnectionWithProps("nullCatalogMeansCurrent=true");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.nullDatabaseMeansCurrent.getKeyName(), "true");
+ Connection con = getConnectionWithProps(props);
try {
this.rs = con.getMetaData().getProcedureColumns(null, null, "testBug3540%", "%");
@@ -117,7 +122,11 @@ public void testBug3540() throws Exception {
public void testBug7026() throws Exception {
createProcedure("testBug7026", "(x int, out y int)\nBEGIN\nSELECT 1;end\n");
- Connection con = getConnectionWithProps("nullCatalogMeansCurrent=true");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.nullDatabaseMeansCurrent.getKeyName(), "true");
+ Connection con = getConnectionWithProps(props);
try {
//
// Should be found this time.
@@ -162,101 +171,103 @@ public void testBug7026() throws Exception {
*/
@Test
public void testBug9319() throws Exception {
- boolean doASelect = true; // SELECT currently causes the server to hang on the last execution of this testcase, filed as BUG#9405
-
- if (isAdminConnectionConfigured()) {
- Connection db2Connection = null;
- Connection db1Connection = null;
-
- db2Connection = getAdminConnection();
- db1Connection = getAdminConnection();
-
- Statement db1st = db1Connection.createStatement();
- Statement db2st = db2Connection.createStatement();
-
- createDatabase(db2st, "db_9319_2");
- db2Connection.setCatalog("db_9319_2");
- createProcedure(db2st, "COMPROVAR_USUARI",
- "(IN p_CodiUsuari VARCHAR(10),\nIN p_contrasenya VARCHAR(10),\nOUT p_userId INTEGER,"
- + "\nOUT p_userName VARCHAR(30),\nOUT p_administrador VARCHAR(1),\nOUT p_idioma VARCHAR(2))\nBEGIN"
- + (doASelect ? "\nselect 2;" : "\nSELECT 2 INTO p_administrador;") + "\nEND");
-
- createDatabase(db1st, "db_9319_1");
- db1Connection.setCatalog("db_9319_1");
- createProcedure(db1st, "COMPROVAR_USUARI",
- "(IN p_CodiUsuari VARCHAR(10),\nIN p_contrasenya VARCHAR(10),\nOUT p_userId INTEGER,"
- + "\nOUT p_userName VARCHAR(30),\nOUT p_administrador VARCHAR(1))\nBEGIN"
- + (doASelect ? "\nselect 1;" : "\nSELECT 1 INTO p_administrador;") + "\nEND");
-
- CallableStatement cstmt = db2Connection.prepareCall("{ call COMPROVAR_USUARI(?, ?, ?, ?, ?, ?) }");
- cstmt.setString(1, "abc");
- cstmt.setString(2, "def");
- cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
- cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
- cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
+ boolean doASelect = true;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- cstmt.registerOutParameter(6, java.sql.Types.VARCHAR);
+ Connection db2Connection = null;
+ Connection db1Connection = null;
- cstmt.execute();
+ db2Connection = getConnectionWithProps(props);
+ db1Connection = getConnectionWithProps(props);
- if (doASelect) {
- this.rs = cstmt.getResultSet();
- assertTrue(this.rs.next());
- assertEquals(2, this.rs.getInt(1));
- } else {
- assertEquals(2, cstmt.getInt(5));
- }
+ Statement db1st = db1Connection.createStatement();
+ Statement db2st = db2Connection.createStatement();
- cstmt = db1Connection.prepareCall("{ call COMPROVAR_USUARI(?, ?, ?, ?, ?, ?) }");
- cstmt.setString(1, "abc");
- cstmt.setString(2, "def");
- cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
- cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
- cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
+ createDatabase(db2st, "db_9319_2");
+ db2Connection.setCatalog("db_9319_2");
- try {
- cstmt.registerOutParameter(6, java.sql.Types.VARCHAR);
- fail("Should've thrown an exception");
- } catch (SQLException sqlEx) {
- assertEquals(MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, sqlEx.getSQLState());
- }
+ createProcedure(db2st, "db_9319_2.COMPROVAR_USUARI",
+ "(IN p_CodiUsuari VARCHAR(10),\nIN p_contrasenya VARCHAR(10),\nOUT p_userId INTEGER,"
+ + "\nOUT p_userName VARCHAR(30),\nOUT p_administrador VARCHAR(1),\nOUT p_idioma VARCHAR(2))\nBEGIN"
+ + (doASelect ? "\nselect 2;" : "\nSELECT 2 INTO p_administrador;") + "\nEND");
- cstmt = db1Connection.prepareCall("{ call COMPROVAR_USUARI(?, ?, ?, ?, ?) }");
- cstmt.setString(1, "abc");
- cstmt.setString(2, "def");
- cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
- cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
- cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
+ createDatabase(db1st, "db_9319_1");
+ db1Connection.setCatalog("db_9319_1");
+ createProcedure(db1st, "db_9319_1.COMPROVAR_USUARI",
+ "(IN p_CodiUsuari VARCHAR(10),\nIN p_contrasenya VARCHAR(10),\nOUT p_userId INTEGER,"
+ + "\nOUT p_userName VARCHAR(30),\nOUT p_administrador VARCHAR(1))\nBEGIN"
+ + (doASelect ? "\nselect 1;" : "\nSELECT 1 INTO p_administrador;") + "\nEND");
- cstmt.execute();
+ CallableStatement cstmt = db2Connection.prepareCall("{ call COMPROVAR_USUARI(?, ?, ?, ?, ?, ?) }");
+ cstmt.setString(1, "abc");
+ cstmt.setString(2, "def");
+ cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
+ cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
+ cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
- if (doASelect) {
- this.rs = cstmt.getResultSet();
- assertTrue(this.rs.next());
- assertEquals(1, this.rs.getInt(1));
- } else {
- assertEquals(1, cstmt.getInt(5));
- }
+ cstmt.registerOutParameter(6, java.sql.Types.VARCHAR);
- String quoteChar = db2Connection.getMetaData().getIdentifierQuoteString();
+ cstmt.execute();
- cstmt = db2Connection.prepareCall(
- "{ call " + quoteChar + db1Connection.getCatalog() + quoteChar + "." + quoteChar + "COMPROVAR_USUARI" + quoteChar + "(?, ?, ?, ?, ?) }");
- cstmt.setString(1, "abc");
- cstmt.setString(2, "def");
- cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
- cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
- cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
+ if (doASelect) {
+ this.rs = cstmt.getResultSet();
+ assertTrue(this.rs.next());
+ assertEquals(2, this.rs.getInt(1));
+ } else {
+ assertEquals(2, cstmt.getInt(5));
+ }
- cstmt.execute();
+ cstmt = db1Connection.prepareCall("{ call COMPROVAR_USUARI(?, ?, ?, ?, ?, ?) }");
+ cstmt.setString(1, "abc");
+ cstmt.setString(2, "def");
+ cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
+ cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
+ cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
- if (doASelect) {
- this.rs = cstmt.getResultSet();
- assertTrue(this.rs.next());
- assertEquals(1, this.rs.getInt(1));
- } else {
- assertEquals(1, cstmt.getInt(5));
- }
+ try {
+ cstmt.registerOutParameter(6, java.sql.Types.VARCHAR);
+ fail("Should've thrown an exception");
+ } catch (SQLException sqlEx) {
+ assertEquals(MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, sqlEx.getSQLState());
+ }
+
+ cstmt = db1Connection.prepareCall("{ call COMPROVAR_USUARI(?, ?, ?, ?, ?) }");
+ cstmt.setString(1, "abc");
+ cstmt.setString(2, "def");
+ cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
+ cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
+ cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
+
+ cstmt.execute();
+
+ if (doASelect) {
+ this.rs = cstmt.getResultSet();
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+ } else {
+ assertEquals(1, cstmt.getInt(5));
+ }
+
+ String quoteChar = db2Connection.getMetaData().getIdentifierQuoteString();
+
+ cstmt = db2Connection.prepareCall(
+ "{ call " + quoteChar + db1Connection.getCatalog() + quoteChar + "." + quoteChar + "COMPROVAR_USUARI" + quoteChar + "(?, ?, ?, ?, ?) }");
+ cstmt.setString(1, "abc");
+ cstmt.setString(2, "def");
+ cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
+ cstmt.registerOutParameter(4, java.sql.Types.VARCHAR);
+ cstmt.registerOutParameter(5, java.sql.Types.VARCHAR);
+
+ cstmt.execute();
+
+ if (doASelect) {
+ this.rs = cstmt.getResultSet();
+ assertTrue(this.rs.next());
+ assertEquals(1, this.rs.getInt(1));
+ } else {
+ assertEquals(1, cstmt.getInt(5));
}
}
@@ -432,31 +443,28 @@ public void testBug12417() throws Exception {
@Test
public void testBug15121() throws Exception {
- if (!this.DISABLED_testBug15121 /* needs to be fixed on server */) {
- createProcedure("p_testBug15121", "()\nBEGIN\nSELECT * from idonotexist;\nEND");
+ createProcedure("p_testBug15121", "()\nBEGIN\nSELECT * from idonotexist;\nEND");
- Properties props = new Properties();
- props.setProperty(PropertyKey.DBNAME.getKeyName(), "");
-
- Connection noDbConn = null;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.DBNAME.getKeyName(), "");
- try {
- noDbConn = getConnectionWithProps(props);
+ Connection noDbConn = getConnectionWithProps(props);
- StringBuilder queryBuf = new StringBuilder("{call ");
- String quotedId = this.conn.getMetaData().getIdentifierQuoteString();
- queryBuf.append(quotedId);
- queryBuf.append(this.conn.getCatalog());
- queryBuf.append(quotedId);
- queryBuf.append(".p_testBug15121()}");
+ StringBuilder queryBuf = new StringBuilder("{call ");
+ String quotedId = this.conn.getMetaData().getIdentifierQuoteString();
+ queryBuf.append(quotedId);
+ queryBuf.append(this.conn.getCatalog());
+ queryBuf.append(quotedId);
+ queryBuf.append(".p_testBug15121()}");
+ assertThrows(SQLException.class, "Table '" + this.conn.getCatalog() + ".idonotexist' doesn't exist", new Callable() {
+ public Void call() throws Exception {
noDbConn.prepareCall(queryBuf.toString()).execute();
- } finally {
- if (noDbConn != null) {
- noDbConn.close();
- }
+ return null;
}
- }
+ });
}
/**
@@ -872,7 +880,11 @@ public void testBug28689() throws Exception {
createProcedure("sp_testBug28689", "(tid INT)\nBEGIN\nUPDATE testBug28689 SET usuario = 'BBBBBB' WHERE id = tid;\nEND");
- Connection noProcedureBodiesConn = getConnectionWithProps("noAccessToProcedureBodies=true");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.noAccessToProcedureBodies.getKeyName(), "true");
+ Connection noProcedureBodiesConn = getConnectionWithProps(props);
CallableStatement cStmt = null;
try {
@@ -1120,7 +1132,14 @@ public void testBug49831() throws Exception {
execProcBug49831(this.conn);
this.stmt.execute("TRUNCATE TABLE testBug49831");
assertEquals(0, getRowCount("testBug49831"));
- Connection noBodiesConn = getConnectionWithProps("noAccessToProcedureBodies=true,jdbcCompliantTruncation=false,characterEncoding=utf8");
+
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.noAccessToProcedureBodies.getKeyName(), "true");
+ props.setProperty(PropertyKey.jdbcCompliantTruncation.getKeyName(), "false");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "utf8");
+ Connection noBodiesConn = getConnectionWithProps(props);
try {
execProcBug49831(noBodiesConn);
} finally {
@@ -1183,6 +1202,8 @@ public void testBug43576() throws Exception {
+ "\nOUT fdoc VARCHAR(100))\nBEGIN\nSET nfact = 'ncfact string';\nSET ffact = 'ffact string';\nSET fdoc = 'fdoc string';\nEND");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.jdbcCompliantTruncation.getKeyName(), "true");
props.setProperty(PropertyKey.useInformationSchema.getKeyName(), "true");
Connection conn1 = null;
@@ -1484,7 +1505,9 @@ public void testBug26259384() throws Exception {
createProcedure("testBug26259384", "(IN p1 int,INOUT p2 int)\nBEGIN\nSET p2=p1+100;\nEND");
Properties props = new Properties();
- props.setProperty("autoReconnect", "true");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
Connection conn1 = getConnectionWithProps(props);
conn1.prepareCall("{ call testBug26259384(?+?,?) }");
@@ -1501,7 +1524,7 @@ public void testBug87704() throws Exception {
"(IN PARAMIN BIGINT, OUT PARAM_OUT_LONG BIGINT, OUT PARAM_OUT_STR VARCHAR(100))\nBEGIN\nSET PARAM_OUT_LONG = PARAMIN + 100000;\nSET PARAM_OUT_STR = concat('STR' ,PARAM_OUT_LONG);end\n");
final Properties props = new Properties();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "true");
props.setProperty(PropertyKey.cachePrepStmts.getKeyName(), "true");
@@ -1536,4 +1559,88 @@ public void testBug87704() throws Exception {
}
}
}
+
+ /**
+ * Tests fix for Bug#20279641, CANNOT CALL A PROCEDURE USING `DATABASE`.PROCNAME FORMAT.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug20279641() throws Exception {
+ createDatabase("`abc1`");
+ createProcedure("`abc1`.procBug20279641", "(IN c1 int, INOUT c2 int, OUT c3 int)" + " BEGIN Set c3=c2+c1; END");
+
+ CallableStatement cstmt = this.conn.prepareCall("{ call `abc1`.procBug20279641(?, ?, ?) }");
+ cstmt.registerOutParameter(2, java.sql.Types.INTEGER);
+ cstmt.registerOutParameter(3, java.sql.Types.INTEGER);
+ cstmt.setInt(1, 113);
+ cstmt.setInt(2, 123);
+ cstmt.setNull(3, java.sql.Types.INTEGER);
+ cstmt.execute();
+
+ assertEquals("123", cstmt.getString(2));
+ assertEquals("236", cstmt.getString(3));
+ }
+
+ /**
+ * Tests fix for Bug#19857166, SET FUNCTIONS ON CALLABLESTATEMENT RETURNS EXCEPTION WHEN CALLED WITH PARAM NAME.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug19857166() throws Exception {
+ createProcedure("testBug19857166p", "(IN inp1 VARCHAR(10),INOUT inp2 VARCHAR(10)) begin" + " set inp2 = 'data'; END");
+ createFunction("testBug19857166f", "(a char(10),b varchar(10)) RETURNS CHAR(50) COMMENT 'Returns string' DETERMINISTIC BEGIN RETURN CONCAT(a, b); END");
+
+ Connection con = null;
+ try {
+ for (boolean getProcRetFuncs : new boolean[] { false, true }) {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.getProceduresReturnsFunctions.getKeyName(), "" + getProcRetFuncs);
+ con = getConnectionWithProps(props);
+
+ CallableStatement callSt1 = con.prepareCall(" call testBug19857166p(?, ?) ");
+ assertThrows(SQLException.class, "No parameter named 'iNp1'", () -> {
+ callSt1.setString("iNp1", "xxx");
+ return null;
+ });
+ assertThrows(SQLException.class, "No parameter named 'inP2'", () -> {
+ callSt1.setString("inP2", "xxx");
+ return null;
+ });
+ callSt1.setString("inp1", "xxx");
+ callSt1.registerOutParameter(2, java.sql.Types.VARCHAR);
+ callSt1.execute();
+ assertEquals("data", callSt1.getString(2));
+ callSt1.close();
+
+ CallableStatement callSt2 = con.prepareCall("{? = CALL testBug19857166f(?,?)}");
+ callSt2.registerOutParameter(1, java.sql.Types.VARCHAR);
+ if (getProcRetFuncs) {
+ callSt2.setString("a", "abcd");
+ callSt2.setString("b", "rr");
+ } else {
+ assertThrows(SQLException.class, "No parameter named 'a'", () -> {
+ callSt2.setString("a", "abcd");
+ return null;
+ });
+ assertThrows(SQLException.class, "No parameter named 'b'", () -> {
+ callSt2.setString("b", "rr");
+ return null;
+ });
+ callSt2.setString(2, "abcd");
+ callSt2.setString(3, "rr");
+ }
+ callSt2.execute();
+ assertEquals("abcdrr", callSt2.getString(1), "Data Comparison failed");
+ callSt2.close();
+ }
+ } finally {
+ if (con != null) {
+ con.close();
+ }
+ }
+ }
}
diff --git a/src/test/java/testsuite/regression/CharsetRegressionTest.java b/src/test/java/testsuite/regression/CharsetRegressionTest.java
index d9ea76423..5338d0a91 100644
--- a/src/test/java/testsuite/regression/CharsetRegressionTest.java
+++ b/src/test/java/testsuite/regression/CharsetRegressionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2020, Oracle and/or its affiliates.
+ * Copyright (c) 2014, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -32,28 +32,615 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
-import com.mysql.cj.CharsetMapping;
+import com.mysql.cj.CacheAdapter;
+import com.mysql.cj.CharsetMappingWrapper;
+import com.mysql.cj.CharsetSettings;
import com.mysql.cj.MysqlConnection;
+import com.mysql.cj.NativeSession;
import com.mysql.cj.Query;
+import com.mysql.cj.ServerVersion;
+import com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm;
+import com.mysql.cj.conf.PropertyDefinitions.SslMode;
import com.mysql.cj.conf.PropertyKey;
import com.mysql.cj.exceptions.ExceptionFactory;
+import com.mysql.cj.exceptions.MysqlErrorNumbers;
+import com.mysql.cj.interceptors.QueryInterceptor;
+import com.mysql.cj.jdbc.JdbcConnection;
+import com.mysql.cj.log.Log;
+import com.mysql.cj.protocol.Message;
import com.mysql.cj.protocol.Resultset;
+import com.mysql.cj.util.StringUtils;
import testsuite.BaseQueryInterceptor;
import testsuite.BaseTestCase;
public class CharsetRegressionTest extends BaseTestCase {
+
+ /**
+ * Tests fix for BUG#7607 - MS932, SHIFT_JIS and Windows_31J not recog. as aliases for sjis.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug7607() throws Exception {
+ Connection ms932Conn = null, cp943Conn = null, shiftJisConn = null, windows31JConn = null;
+
+ try {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "MS932");
+
+ ms932Conn = getConnectionWithProps(props);
+
+ this.rs = ms932Conn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
+ assertTrue(this.rs.next());
+ String encoding = this.rs.getString(2);
+ assertEquals("cp932", encoding.toLowerCase(Locale.ENGLISH));
+
+ this.rs = ms932Conn.createStatement().executeQuery("SELECT 'abc'");
+ assertTrue(this.rs.next());
+
+ String charsetToCheck = "ms932";
+
+ assertEquals(charsetToCheck,
+ ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toLowerCase(Locale.ENGLISH));
+
+ try {
+ ms932Conn.createStatement().executeUpdate("drop table if exists testBug7607");
+ ms932Conn.createStatement().executeUpdate("create table testBug7607 (sortCol int, col1 varchar(100) ) character set sjis");
+ ms932Conn.createStatement().executeUpdate("insert into testBug7607 values(1, 0x835C)"); // standard
+ // sjis
+ ms932Conn.createStatement().executeUpdate("insert into testBug7607 values(2, 0x878A)"); // NEC
+ // kanji
+
+ this.rs = ms932Conn.createStatement().executeQuery("SELECT col1 FROM testBug7607 ORDER BY sortCol ASC");
+ assertTrue(this.rs.next());
+ String asString = this.rs.getString(1);
+ assertTrue("\u30bd".equals(asString));
+
+ assertTrue(this.rs.next());
+ asString = this.rs.getString(1);
+ assertEquals("\u3231", asString);
+ } finally {
+ ms932Conn.createStatement().executeUpdate("drop table if exists testBug7607");
+ }
+
+ props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "SHIFT_JIS");
+
+ shiftJisConn = getConnectionWithProps(props);
+
+ this.rs = shiftJisConn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
+ assertTrue(this.rs.next());
+ encoding = this.rs.getString(2);
+ assertTrue("sjis".equalsIgnoreCase(encoding));
+
+ this.rs = shiftJisConn.createStatement().executeQuery("SELECT 'abc'");
+ assertTrue(this.rs.next());
+
+ String charSetUC = ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toUpperCase(Locale.US);
+
+ props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "WINDOWS-31J");
+
+ windows31JConn = getConnectionWithProps(props);
+
+ this.rs = windows31JConn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
+ assertTrue(this.rs.next());
+ encoding = this.rs.getString(2);
+
+ assertEquals("cp932", encoding.toLowerCase(Locale.ENGLISH));
+
+ this.rs = windows31JConn.createStatement().executeQuery("SELECT 'abc'");
+ assertTrue(this.rs.next());
+
+ assertEquals("windows-31j".toLowerCase(Locale.ENGLISH),
+ ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toLowerCase(Locale.ENGLISH));
+
+ props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "CP943");
+
+ cp943Conn = getConnectionWithProps(props);
+
+ this.rs = cp943Conn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
+ assertTrue(this.rs.next());
+ encoding = this.rs.getString(2);
+ assertTrue("sjis".equalsIgnoreCase(encoding));
+
+ this.rs = cp943Conn.createStatement().executeQuery("SELECT 'abc'");
+ assertTrue(this.rs.next());
+
+ charSetUC = ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toUpperCase(Locale.US);
+
+ assertEquals("CP943", charSetUC);
+
+ } finally {
+ if (ms932Conn != null) {
+ ms932Conn.close();
+ }
+
+ if (shiftJisConn != null) {
+ shiftJisConn.close();
+ }
+
+ if (windows31JConn != null) {
+ windows31JConn.close();
+ }
+
+ if (cp943Conn != null) {
+ cp943Conn.close();
+ }
+ }
+ }
+
+ /**
+ * Tests fix for BUG#9206, can not use 'UTF-8' for characterSetResults configuration property.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug9206() throws Exception {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "UTF-8");
+ getConnectionWithProps(props).close();
+ }
+
+ /**
+ * Tests fix for BUG#10496 - SQLException is thrown when using property "characterSetResults"
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug10496() throws Exception {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "WINDOWS-31J");
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "WINDOWS-31J");
+ getConnectionWithProps(props).close();
+
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "EUC_JP");
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "EUC_JP");
+ getConnectionWithProps(props).close();
+ }
+
+ /**
+ * Tests fix for BUG#12752 - Cp1251 incorrectly mapped to win1251 for servers newer than 4.0.x.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug12752() throws Exception {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "Cp1251");
+ getConnectionWithProps(props).close();
+ }
+
+ /**
+ * Tests fix for BUG#15544, no "dos" character set in MySQL > 4.1.0
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug15544() throws Exception {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "Cp437");
+ Connection dosConn = null;
+
+ try {
+ dosConn = getConnectionWithProps(props);
+ } finally {
+ if (dosConn != null) {
+ dosConn.close();
+ }
+ }
+ }
+
+ @Test
+ public void testBug37931() throws Exception {
+ Connection _conn = null;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "ISO88591");
+
+ try {
+ _conn = getConnectionWithProps(props);
+ assertTrue(false, "This point should not be reached.");
+ } catch (Exception e) {
+ assertEquals("Unsupported character encoding 'ISO88591'", e.getMessage());
+ } finally {
+ if (_conn != null) {
+ _conn.close();
+ }
+ }
+
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "null");
+
+ try {
+ _conn = getConnectionWithProps(props);
+
+ Statement _stmt = _conn.createStatement();
+ ResultSet _rs = _stmt.executeQuery("show variables where variable_name='character_set_results'");
+ if (_rs.next()) {
+ String res = _rs.getString(2);
+ if (res == null || "NULL".equalsIgnoreCase(res) || res.length() == 0) {
+ assertTrue(true);
+ } else {
+ assertTrue(false);
+ }
+ }
+ } finally {
+ if (_conn != null) {
+ _conn.close();
+ }
+ }
+ }
+
+ /**
+ * Tests fix for Bug#64205 (13702427), Connected through Connector/J 5.1 to MySQL 5.5, the error message is garbled.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug64205() throws Exception {
+ Properties props = getPropertiesFromTestsuiteUrl();
+ String dbname = props.getProperty(PropertyKey.DBNAME.getKeyName());
+ if (dbname == null) {
+ assertTrue(false, "No database selected");
+ }
+
+ props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "EUC_JP");
+
+ Connection testConn = null;
+ Statement testSt = null;
+ ResultSet testRs = null;
+ try {
+ testConn = getConnectionWithProps(props);
+ testSt = testConn.createStatement();
+ testRs = testSt.executeQuery("SELECT * FROM `" + dbname + "`.`\u307b\u3052\u307b\u3052`");
+ } catch (SQLException e1) {
+ if (e1.getClass().getName().endsWith("SQLSyntaxErrorException")) {
+ assertEquals("Table '" + dbname + ".\u307B\u3052\u307b\u3052' doesn't exist", e1.getMessage());
+ } else if (e1.getErrorCode() == MysqlErrorNumbers.ER_FILE_NOT_FOUND) {
+ // this could happen on Windows with 5.5 and 5.6 servers where BUG#14642248 exists
+ assertTrue(e1.getMessage().contains("Can't find file"));
+ } else {
+ throw e1;
+ }
+
+ testSt.close();
+ testConn.close();
+
+ try {
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "SJIS");
+ testConn = getConnectionWithProps(props);
+ testSt = testConn.createStatement();
+ testSt.execute("SET lc_messages = 'ru_RU'");
+ testRs = testSt.executeQuery("SELECT * FROM `" + dbname + "`.`\u307b\u3052\u307b\u3052`");
+ } catch (SQLException e2) {
+ if (e2.getClass().getName().endsWith("SQLSyntaxErrorException")) {
+ assertEquals("\u0422\u0430\u0431\u043b\u0438\u0446\u0430 '" + dbname
+ + ".\u307b\u3052\u307b\u3052' \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442", e2.getMessage());
+ } else if (e2.getErrorCode() == MysqlErrorNumbers.ER_FILE_NOT_FOUND) {
+ // this could happen on Windows with 5.5 and 5.6 servers where BUG#14642248 exists
+ assertTrue(e2.getMessage().indexOf("\u0444\u0430\u0439\u043b") > -1,
+ "File not found error message should be russian but is this one: " + e2.getMessage());
+ } else {
+ throw e2;
+ }
+ }
+
+ } finally {
+ if (testRs != null) {
+ testRs.close();
+ }
+ if (testSt != null) {
+ testSt.close();
+ }
+ if (testConn != null) {
+ testConn.close();
+ }
+ }
+
+ // also test with explicit characterSetResults and cacheServerConfiguration
+ try {
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "EUC_JP");
+ props.setProperty(PropertyKey.cacheServerConfiguration.getKeyName(), "true");
+ testConn = getConnectionWithProps(props);
+ testSt = testConn.createStatement();
+ testRs = testSt.executeQuery("SELECT * FROM `" + dbname + "`.`\u307b\u3052\u307b\u3052`");
+ fail("Exception should be thrown for attemping to query non-existing table");
+ } catch (SQLException e1) {
+ if (e1.getClass().getName().endsWith("SQLSyntaxErrorException")) {
+ assertEquals("Table '" + dbname + ".\u307B\u3052\u307b\u3052' doesn't exist", e1.getMessage());
+ } else if (e1.getErrorCode() == MysqlErrorNumbers.ER_FILE_NOT_FOUND) {
+ // this could happen on Windows with 5.5 and 5.6 servers where BUG#14642248 exists
+ assertTrue(e1.getMessage().contains("Can't find file"));
+ } else {
+ throw e1;
+ }
+ } finally {
+ testConn.close();
+ }
+ props.remove(PropertyKey.cacheServerConfiguration.getKeyName());
+
+ // Error messages may also be received after the handshake but before connection initialization is complete. This tests the interpretation of
+ // errors thrown during this time window using a SatementInterceptor that throws an Exception while setting the session variables.
+ // Start by getting the Latin1 version of the error to compare later.
+ String latin1ErrorMsg = "";
+ int latin1ErrorLen = 0;
+ try {
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "Latin1");
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "Latin1");
+ props.setProperty(PropertyKey.sessionVariables.getKeyName(), "lc_messages=ru_RU");
+ props.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestBug64205QueryInterceptor.class.getName());
+ testConn = getConnectionWithProps(props);
+ fail("Exception should be trown for syntax error, caused by the exception interceptor");
+ } catch (Exception e) {
+ latin1ErrorMsg = e.getMessage();
+ latin1ErrorLen = latin1ErrorMsg.length();
+ }
+ // Now compare with results when using a proper encoding.
+ try {
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "EUC_JP");
+ props.setProperty(PropertyKey.characterSetResults.getKeyName(), "EUC_JP");
+ props.setProperty(PropertyKey.sessionVariables.getKeyName(), "lc_messages=ru_RU");
+ props.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestBug64205QueryInterceptor.class.getName());
+ testConn = getConnectionWithProps(props);
+ fail("Exception should be trown for syntax error, caused by the exception interceptor");
+ } catch (SQLException e) {
+ // There should be the Russian version of this error message, correctly encoded. A mis-interpretation, e.g. decoding as latin1, would return a
+ // wrong message with the wrong size.
+ assertEquals(29 + dbname.length(), e.getMessage().length());
+ assertFalse(latin1ErrorMsg.equals(e.getMessage()));
+ assertFalse(latin1ErrorLen == e.getMessage().length());
+ } finally {
+ testConn.close();
+ }
+ }
+
+ public static class TestBug64205QueryInterceptor extends BaseQueryInterceptor {
+ private JdbcConnection connection;
+
+ @Override
+ public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
+ this.connection = (JdbcConnection) conn;
+ return super.init(conn, props, log);
+ }
+
+ @Override
+ public M postProcess(M queryPacket, M originalResponsePacket) {
+ String sql = StringUtils.toString(queryPacket.getByteBuffer(), 1, (queryPacket.getPosition() - 1));
+ if (sql.contains("lc_messages=ru_RU")) {
+ try {
+ this.connection.createStatement()
+ .executeQuery("SELECT * FROM `"
+ + (this.connection.getPropertySet().getEnumProperty(PropertyKey.databaseTerm)
+ .getValue() == DatabaseTerm.SCHEMA ? this.connection.getSchema() : this.connection.getCatalog())
+ + "`.`\u307b\u3052\u307b\u3052`");
+ } catch (Exception e) {
+ throw ExceptionFactory.createException(e.getMessage(), e);
+ }
+ }
+ return originalResponsePacket;
+ }
+ }
+
+ /**
+ * Bug #41730 - SQL Injection when using U+00A5 and SJIS/Windows-31J
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug41730() throws Exception {
+ try {
+ "".getBytes("sjis");
+ } catch (UnsupportedEncodingException ex) {
+ assumeFalse(true, "Test requires JVM with sjis support.");
+ }
+
+ Connection conn2 = null;
+ PreparedStatement pstmt2 = null;
+ try {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "sjis");
+ conn2 = getConnectionWithProps(props);
+ pstmt2 = conn2.prepareStatement("select ?");
+ pstmt2.setString(1, "\u00A5'");
+ // this will throw an exception with a syntax error if it fails
+ this.rs = pstmt2.executeQuery();
+ } finally {
+ try {
+ if (pstmt2 != null) {
+ pstmt2.close();
+ }
+ } catch (SQLException ex) {
+ }
+ try {
+ if (conn2 != null) {
+ conn2.close();
+ }
+ } catch (SQLException ex) {
+ }
+ }
+ }
+
+ /**
+ * Tests character conversion bug.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testAsciiCharConversion() throws Exception {
+ byte[] buf = new byte[10];
+ buf[0] = (byte) '?';
+ buf[1] = (byte) 'S';
+ buf[2] = (byte) 't';
+ buf[3] = (byte) 'a';
+ buf[4] = (byte) 't';
+ buf[5] = (byte) 'e';
+ buf[6] = (byte) '-';
+ buf[7] = (byte) 'b';
+ buf[8] = (byte) 'o';
+ buf[9] = (byte) 't';
+
+ String testString = "?State-bot";
+ String convertedString = StringUtils.toAsciiString(buf);
+
+ for (int i = 0; i < convertedString.length(); i++) {
+ System.out.println((byte) convertedString.charAt(i));
+ }
+
+ assertTrue(testString.equals(convertedString), "Converted string != test string");
+ }
+
+ /**
+ * Tests for regression of encoding forced by user, reported by Jive Software
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testEncodingRegression() throws Exception {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ DriverManager.getConnection(dbUrl, props).close();
+ }
+
+ /**
+ * Tests fix for BUG#879
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testEscapeSJISDoubleEscapeBug() throws Exception {
+ String testString = "'It\\'s a boy!'";
+
+ //byte[] testStringAsBytes = testString.getBytes("SJIS");
+
+ byte[] origByteStream = new byte[] { (byte) 0x95, (byte) 0x5c, (byte) 0x8e, (byte) 0x96, (byte) 0x5c, (byte) 0x62, (byte) 0x5c };
+
+ //String origString = "\u955c\u8e96\u5c62\\";
+
+ origByteStream = new byte[] { (byte) 0x8d, (byte) 0xb2, (byte) 0x93, (byte) 0x91, (byte) 0x81, (byte) 0x40, (byte) 0x8c, (byte) 0x5c };
+
+ testString = new String(origByteStream, "SJIS");
+
+ Properties connProps = new Properties();
+ connProps.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ connProps.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ connProps.setProperty(PropertyKey.characterEncoding.getKeyName(), "sjis");
+
+ Connection sjisConn = getConnectionWithProps(connProps);
+ Statement sjisStmt = sjisConn.createStatement();
+
+ try {
+ sjisStmt.executeUpdate("DROP TABLE IF EXISTS doubleEscapeSJISTest");
+ sjisStmt.executeUpdate("CREATE TABLE doubleEscapeSJISTest (field1 BLOB)");
+
+ PreparedStatement sjisPStmt = sjisConn.prepareStatement("INSERT INTO doubleEscapeSJISTest VALUES (?)");
+ sjisPStmt.setString(1, testString);
+ sjisPStmt.executeUpdate();
+
+ this.rs = sjisStmt.executeQuery("SELECT * FROM doubleEscapeSJISTest");
+
+ this.rs.next();
+
+ String retrString = this.rs.getString(1);
+
+ System.out.println(retrString.equals(testString));
+ } finally {
+ sjisStmt.executeUpdate("DROP TABLE IF EXISTS doubleEscapeSJISTest");
+ }
+ }
+
+ @Test
+ public void testGreekUtf8411() throws Exception {
+ Properties newProps = new Properties();
+ newProps.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ newProps.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ newProps.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+
+ Connection utf8Conn = this.getConnectionWithProps(newProps);
+
+ Statement utfStmt = utf8Conn.createStatement();
+
+ createTable("greekunicode", "(ID INTEGER NOT NULL AUTO_INCREMENT,UpperCase VARCHAR (30),LowerCase VARCHAR (30),Accented "
+ + " VARCHAR (30),Special VARCHAR (30),PRIMARY KEY(ID)) DEFAULT CHARACTER SET utf8", "InnoDB");
+
+ String upper = "\u0394\u930F\u039A\u0399\u039C\u0397";
+ String lower = "\u03B4\u03BF\u03BA\u03B9\u03BC\u03B7";
+ String accented = "\u03B4\u03CC\u03BA\u03AF\u03BC\u03AE";
+ String special = "\u037E\u03C2\u03B0";
+
+ utfStmt.executeUpdate("INSERT INTO greekunicode VALUES ('1','" + upper + "','" + lower + "','" + accented + "','" + special + "')");
+
+ this.rs = utfStmt.executeQuery("SELECT UpperCase, LowerCase, Accented, Special from greekunicode");
+
+ this.rs.next();
+
+ assertTrue(upper.equals(this.rs.getString(1)));
+ assertTrue(lower.equals(this.rs.getString(2)));
+ assertTrue(accented.equals(this.rs.getString(3)));
+ assertTrue(special.equals(this.rs.getString(4)));
+ }
+
+ /**
+ * Tests fix for BUG#24840 - character encoding of "US-ASCII" doesn't map correctly for 4.1 or newer
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug24840() throws Exception {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "US-ASCII");
+
+ getConnectionWithProps(props).close();
+ }
+
/**
* Tests fix for Bug#73663 (19479242), utf8mb4 does not work for connector/j >=5.1.13
*
@@ -68,30 +655,34 @@ public void testBug73663() throws Exception {
this.rs.next();
String collation = this.rs.getString(2);
- if (collation != null && collation.startsWith("utf8mb4")
- && "utf8mb4".equals(((MysqlConnection) this.conn).getSession().getServerSession().getServerVariable("character_set_server"))) {
- Properties p = new Properties();
- p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
- p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug73663QueryInterceptor.class.getName());
+ assumeTrue(
+ collation != null && collation.startsWith("utf8mb4")
+ && "utf8mb4".equals(((MysqlConnection) this.conn).getSession().getServerSession().getServerVariable("character_set_server")),
+ "This test requires server configured with character_set_server=utf8mb4 and collation-server set to one of utf8mb4 collations.");
- getConnectionWithProps(p);
- // exception will be thrown from the statement interceptor if any "SET NAMES utf8" statement is issued instead of "SET NAMES utf8mb4"
- } else {
- System.out.println(
- "testBug73663 was skipped: This test is only run when character_set_server=utf8mb4 and collation-server set to one of utf8mb4 collations.");
- }
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug73663QueryInterceptor.class.getName());
+
+ getConnectionWithProps(p);
+ // failure will be thrown from the statement interceptor if any "SET NAMES utf8" statement is issued instead of "SET NAMES utf8mb4"
}
/**
* Statement interceptor used to implement preceding test.
*/
public static class Bug73663QueryInterceptor extends BaseQueryInterceptor {
+ @Override
+ public M preProcess(M queryPacket) {
+ String sql = StringUtils.toString(queryPacket.getByteBuffer(), 1, (queryPacket.getPosition() - 1));
+ assertFalse(sql.contains("SET NAMES utf8") && !sql.contains("utf8mb4"), "Character set statement issued: " + sql);
+ return null;
+ }
+
@Override
public T preProcess(Supplier str, Query interceptedQuery) {
String sql = str.get();
- if (sql.contains("SET NAMES utf8") && !sql.contains("utf8mb4")) {
- throw ExceptionFactory.createException("Character set statement issued: " + sql);
- }
+ assertFalse(sql.contains("SET NAMES utf8") && !sql.contains("utf8mb4"), "Character set statement issued: " + sql);
return null;
}
}
@@ -150,12 +741,12 @@ public Void call() throws Exception {
*/
@Test
public void testBug25504578() throws Exception {
-
- Properties p = new Properties();
- String cjCharset = CharsetMapping.getJavaEncodingForMysqlCharset("latin7");
- p.setProperty(PropertyKey.characterEncoding.getKeyName(), cjCharset);
-
- getConnectionWithProps(p);
+ String cjCharset = CharsetMappingWrapper.getStaticJavaEncodingForMysqlCharset("latin7");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), cjCharset);
+ getConnectionWithProps(props);
}
/**
@@ -173,11 +764,13 @@ public void testBug81196() throws Exception {
"(`id` int AUTO_INCREMENT NOT NULL, `name` varchar(50) NULL," + "CONSTRAINT `PK_LastViewedMatch_id` PRIMARY KEY (`id`))"
+ " ENGINE=InnoDB AUTO_INCREMENT=1 CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci");
- Properties p = new Properties();
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
/* With a single-byte encoding */
- p.setProperty(PropertyKey.characterEncoding.getKeyName(), CharsetMapping.getJavaEncodingForMysqlCharset("latin1"));
- Connection conn1 = getConnectionWithProps(p);
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), CharsetMappingWrapper.getStaticJavaEncodingForMysqlCharset("latin1"));
+ Connection conn1 = getConnectionWithProps(props);
Statement st1 = conn1.createStatement();
st1.executeUpdate("INSERT INTO testBug81196(name) VALUES ('" + fourBytesValue + "')");
ResultSet rs1 = st1.executeQuery("SELECT * from testBug81196");
@@ -186,8 +779,8 @@ public void testBug81196() throws Exception {
/* With a UTF-8 encoding */
st1.executeUpdate("TRUNCATE TABLE testBug81196");
- p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
- Connection conn2 = getConnectionWithProps(p);
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ Connection conn2 = getConnectionWithProps(props);
Statement st2 = conn2.createStatement();
st2.executeUpdate("INSERT INTO testBug81196(name) VALUES ('" + fourBytesValue + "')");
ResultSet rs2 = st2.executeQuery("SELECT * from testBug81196");
@@ -196,9 +789,9 @@ public void testBug81196() throws Exception {
/* With a UTF-8 encoding and connectionCollation=utf8mb4_unicode_ci */
st1.executeUpdate("TRUNCATE TABLE testBug81196");
- p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
- p.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8mb4_unicode_ci");
- Connection conn2_1 = getConnectionWithProps(p);
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ props.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8mb4_unicode_ci");
+ Connection conn2_1 = getConnectionWithProps(props);
Statement st2_1 = conn2_1.createStatement();
st2_1.executeUpdate("INSERT INTO testBug81196(name) VALUES ('" + fourBytesValue + "')");
ResultSet rs2_1 = st2_1.executeQuery("SELECT * from testBug81196");
@@ -207,9 +800,9 @@ public void testBug81196() throws Exception {
/* With connectionCollation=utf8_bin, SET NAMES utf8 is expected */
st1.executeUpdate("TRUNCATE TABLE testBug81196");
- p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
- p.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8_bin");
- Connection conn3 = getConnectionWithProps(p);
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ props.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8_bin");
+ Connection conn3 = getConnectionWithProps(props);
final Statement st3 = conn3.createStatement();
assertThrows(SQLException.class, "Incorrect string value: '\\\\xF0\\\\xA0\\\\x9C\\\\x8E' for column 'name' at row 1", new Callable() {
@@ -220,4 +813,502 @@ public Void call() throws Exception {
});
}
}
+
+ /**
+ * Tests fix for Bug#100606 (31818423), UNECESARY CALL TO "SET NAMES 'UTF8' COLLATE 'UTF8_GENERAL_CI'".
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug100606() throws Exception {
+ this.rs = this.stmt.executeQuery("show variables like 'collation_server'");
+ this.rs.next();
+ String collation = this.rs.getString(2);
+
+ assumeTrue(
+ collation != null && collation.startsWith("utf8_general_ci")
+ && ((MysqlConnection) this.conn).getSession().getServerSession().getServerVariable("character_set_server").startsWith("utf8"),
+ "This test requires server configured with character_set_server=utf8 and collation-server=utf8_general_ci.");
+
+ String fallbackCollation = versionMeetsMinimum(8, 0, 1) ? "utf8mb4_0900_ai_ci" : "utf8mb4_general_ci";
+
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestSetNamesQueryInterceptor.class.getName());
+ checkCollationConnection(p, "SET NAMES", false, fallbackCollation);
+
+ p.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8_general_ci");
+ checkCollationConnection(p, "SET NAMES", false, "utf8_general_ci");
+ }
+
+ /**
+ * Tests fix for Bug#25554464, CONNECT FAILS WITH NPE WHEN THE SERVER STARTED WITH CUSTOM COLLATION.
+ *
+ * This test requires a special server configuration with:
+ *
+ * - character-set-server = custom
+ *
- collation-server = custom_bin
+ *
+ * where 'custom_bin' is not a primary collation for 'custom' character set and has an index == 1024 on MySQL 8.0+ or index == 253 for older servers.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug25554464_1() throws Exception {
+ this.rs = this.stmt.executeQuery("show variables like 'collation_server'");
+ this.rs.next();
+ String collation = this.rs.getString(2);
+ this.rs = this.stmt.executeQuery("select ID from INFORMATION_SCHEMA.COLLATIONS where COLLATION_NAME='custom_bin'");
+
+ assumeTrue(
+ collation != null && collation.startsWith("custom_bin") && this.rs.next() && this.rs.getInt(1) == (versionMeetsMinimum(8, 0, 1) ? 1024 : 253),
+ "This test requires server configured with custom character set and custom_bin collation.");
+
+ String fallbackCollation = versionMeetsMinimum(8, 0, 1) ? "utf8mb4_0900_ai_ci" : "utf8mb4_general_ci";
+
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestSetNamesQueryInterceptor.class.getName());
+
+ // With no specific properties c/J is using a predefined fallback collation 'utf8mb4_0900_ai_ci' or 'utf8mb4_general_ci' depending on server version.
+ // Post-handshake does not issue a SET NAMES because the predefined collation should still be used.
+ checkCollationConnection(p, "SET NAMES", false, fallbackCollation);
+
+ // 'detectCustomCollations' itself doesn't change the expected collation, the predefined one should still be used.
+ p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true");
+ checkCollationConnection(p, "SET NAMES", false, fallbackCollation);
+
+ // The predefined collation should still be used
+ p.setProperty(PropertyKey.customCharsetMapping.getKeyName(), "custom:Cp1252");
+ checkCollationConnection(p, "SET NAMES", false, fallbackCollation);
+
+ // Handshake collation is still 'utf8mb4_0900_ai_ci' because 'custom_bin' index > 255, then c/J sends the SET NAMES for the requested collation in a post-handshake.
+ p.setProperty(PropertyKey.connectionCollation.getKeyName(), "custom_bin");
+ checkCollationConnection(p, "SET NAMES custom COLLATE custom_bin", true, "custom_bin");
+
+ p.setProperty(PropertyKey.connectionCollation.getKeyName(), "custom_general_ci");
+ checkCollationConnection(p, "SET NAMES custom COLLATE custom_general_ci", true, "custom_general_ci");
+
+ // Handshake collation is still 'utf8mb4_0900_ai_ci' because 'Cp1252' is mapped to 'custom' charset via the 'customCharsetMapping' property.
+ // C/J sends the SET NAMES for the requested collation in a post-handshake.
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "Cp1252");
+ p.remove(PropertyKey.connectionCollation.getKeyName());
+ checkCollationConnection(p, "SET NAMES custom", true, "custom_general_ci");
+ }
+
+ /**
+ * Tests fix for Bug#25554464, CONNECT FAILS WITH NPE WHEN THE SERVER STARTED WITH CUSTOM COLLATION.
+ *
+ * This test requires a special server configuration with:
+ *
+ * - character-set-server = custom
+ *
- collation-server = custom_general_ci
+ *
+ * where 'custom_general_ci' is a primary collation for 'custom' character set and has an index == 1025 on MySQL 8.0+ or index == 254 for older servers.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug25554464_2() throws Exception {
+ this.rs = this.stmt.executeQuery("show variables like 'collation_server'");
+ this.rs.next();
+ String collation = this.rs.getString(2);
+
+ this.rs = this.stmt.executeQuery("select ID from INFORMATION_SCHEMA.COLLATIONS where COLLATION_NAME='custom_general_ci'");
+
+ assumeTrue(
+ collation != null && collation.startsWith("custom_general_ci") && this.rs.next()
+ && this.rs.getInt(1) == (versionMeetsMinimum(8, 0, 1) ? 1025 : 254),
+ "This test requires server configured with custom character set and custom_general_ci collation.");
+
+ String fallbackCollation = versionMeetsMinimum(8, 0, 1) ? "utf8mb4_0900_ai_ci" : "utf8mb4_general_ci";
+
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestSetNamesQueryInterceptor.class.getName());
+
+ // With no specific properties c/J is using a predefined fallback collation 'utf8mb4_0900_ai_ci' or 'utf8mb4_general_ci' depending on server version.
+ // Post-handshake does not issue a SET NAMES because the predefined collation should still be used.
+ checkCollationConnection(p, "SET NAMES", false, fallbackCollation);
+
+ // The predefined one should still be used.
+ p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true");
+ p.setProperty(PropertyKey.customCharsetMapping.getKeyName(), "custom:Cp1252");
+ checkCollationConnection(p, "SET NAMES", false, fallbackCollation);
+
+ // Sets the predefined collation via the handshake response, but, in a post-handshake, issues the SET NAMES setting the required 'connectionCollation'.
+ p.setProperty(PropertyKey.connectionCollation.getKeyName(), "custom_general_ci");
+ checkCollationConnection(p, "SET NAMES custom COLLATE custom_general_ci", true, "custom_general_ci");
+
+ // Sets the predefined collation via the handshake response, but, in a post-handshake, issues the SET NAMES setting the required 'characterEncoding'.
+ // The chosen collation then is 'custom_general_ci' because it's a primary one for 'custom' character set.
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "Cp1252");
+ p.remove(PropertyKey.connectionCollation.getKeyName());
+ checkCollationConnection(p, "SET NAMES custom", true, "custom_general_ci");
+ }
+
+ public static class TestSetNamesQueryInterceptor extends BaseQueryInterceptor {
+ public static String query = "";
+ public static boolean usedSetNames = false;
+
+ @Override
+ public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
+ usedSetNames = false;
+ return super.init(conn, props, log);
+ }
+
+ @Override
+ public M preProcess(M queryPacket) {
+ String sql = StringUtils.toString(queryPacket.getByteBuffer(), 1, (queryPacket.getPosition() - 1));
+ if (sql.contains(query)) {
+ usedSetNames = true;
+ }
+ return null;
+ }
+
+ @Override
+ public T preProcess(Supplier str, Query interceptedQuery) {
+ String sql = str.get();
+ if (sql.contains(query)) {
+ usedSetNames = true;
+ }
+ return null;
+ }
+ }
+
+ @Test
+ public void testPasswordCharacterEncoding() throws Exception {
+ this.rs = this.stmt.executeQuery("show variables like 'collation_server'");
+ this.rs.next();
+ String collation = this.rs.getString(2);
+ assumeTrue(collation != null && collation.startsWith("latin1"), "This test requires a server configured with latin1 character set.");
+
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestSetNamesQueryInterceptor.class.getName());
+
+ String requestedCollation = "latin1_swedish_ci";
+ String fallbackCollation = versionMeetsMinimum(8, 0, 1) ? "utf8mb4_0900_ai_ci" : "utf8mb4_general_ci";
+
+ checkCollationConnection(props, "SET NAMES", false, fallbackCollation);
+
+ props.setProperty(PropertyKey.passwordCharacterEncoding.getKeyName(), "UTF-8");
+ checkCollationConnection(props, "SET NAMES", false, fallbackCollation);
+
+ props.setProperty(PropertyKey.connectionCollation.getKeyName(), requestedCollation);
+ checkCollationConnection(props, "SET NAMES latin1 COLLATE " + requestedCollation, true, requestedCollation);
+
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "Cp1252");
+ props.remove(PropertyKey.connectionCollation.getKeyName());
+ checkCollationConnection(props, "SET NAMES latin1", true, requestedCollation);
+
+ requestedCollation = versionMeetsMinimum(8, 0, 1) ? "utf8mb4_0900_ai_ci" : "utf8mb4_general_ci";
+
+ props.setProperty(PropertyKey.connectionCollation.getKeyName(), requestedCollation);
+ checkCollationConnection(props, "SET NAMES", false, requestedCollation);
+
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ props.remove(PropertyKey.connectionCollation.getKeyName());
+ checkCollationConnection(props, "SET NAMES", false, requestedCollation);
+ }
+
+ private void checkCollationConnection(Properties props, String query, boolean expectQueryIsIssued, String expectedCollation) throws Exception {
+ TestSetNamesQueryInterceptor.query = query;
+ Connection c = getConnectionWithProps(props);
+ if (expectQueryIsIssued) {
+ assertTrue(TestSetNamesQueryInterceptor.usedSetNames);
+ } else {
+ assertFalse(TestSetNamesQueryInterceptor.usedSetNames);
+ }
+ this.rs = c.createStatement().executeQuery("show variables like 'collation_connection'");
+ this.rs.next();
+ assertEquals(expectedCollation, this.rs.getString(2));
+ c.close();
+ }
+
+ /**
+ * Tests fix for Bug#71038, Add an option for custom collations detection
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug71038() throws Exception {
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "false");
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug71038QueryInterceptor.class.getName());
+
+ JdbcConnection c = (JdbcConnection) getConnectionWithProps(p);
+ Bug71038QueryInterceptor si = (Bug71038QueryInterceptor) c.getQueryInterceptorsInstances().get(0);
+ assertTrue(si.cnt == 0, "SELECT from INFORMATION_SCHEMA.COLLATIONS was issued when detectCustomCollations=false");
+ c.close();
+
+ p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true");
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug71038QueryInterceptor.class.getName());
+
+ c = (JdbcConnection) getConnectionWithProps(p);
+ si = (Bug71038QueryInterceptor) c.getQueryInterceptorsInstances().get(0);
+ assertTrue(si.cnt > 0, "SELECT from INFORMATION_SCHEMA.COLLATIONS wasn't issued when detectCustomCollations=true");
+ c.close();
+ }
+
+ /**
+ * Counts the number of issued "SHOW COLLATION" statements.
+ */
+ public static class Bug71038QueryInterceptor extends BaseQueryInterceptor {
+ int cnt = 0;
+
+ @Override
+ public M preProcess(M queryPacket) {
+ String sql = StringUtils.toString(queryPacket.getByteBuffer(), 1, (queryPacket.getPosition() - 1));
+ if (sql.contains("from INFORMATION_SCHEMA.COLLATIONS")) {
+ this.cnt++;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Tests fix for Bug#91317 (28207422), Wrong defaults on collation mappings.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug91317() throws Exception {
+ Map defaultCollations = new HashMap<>();
+
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ p.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true");
+ p.setProperty(PropertyKey.customCharsetMapping.getKeyName(), "custom:Cp1252");
+ Connection c = getConnectionWithProps(p);
+
+ // Compare server-side and client-side collation defaults.
+ this.rs = this.stmt.executeQuery("SELECT COLLATION_NAME, CHARACTER_SET_NAME, ID FROM INFORMATION_SCHEMA.COLLATIONS WHERE IS_DEFAULT = 'Yes'");
+ while (this.rs.next()) {
+ String collationName = this.rs.getString(1);
+ String charsetName = this.rs.getString(2);
+ int collationId = this.rs.getInt(3);
+
+ int mappedCollationId = ((MysqlConnection) c).getSession().getServerSession().getCharsetSettings()
+ .getCollationIndexForMysqlCharsetName(charsetName);
+
+ defaultCollations.put(charsetName, collationName);
+
+ // Default collation for 'utf8mb4' is 'utf8mb4_0900_ai_ci' in MySQL 8.0.1 and above, 'utf8mb4_general_ci' in the others.
+ if ("utf8mb4".equalsIgnoreCase(charsetName) && !versionMeetsMinimum(8, 0, 1)) {
+ mappedCollationId = 45;
+ }
+
+ assertEquals(collationId, mappedCollationId);
+ assertEquals(collationName,
+ ((MysqlConnection) c).getSession().getServerSession().getCharsetSettings().getCollationNameForCollationIndex(mappedCollationId));
+ }
+
+ ServerVersion sv = ((JdbcConnection) this.conn).getServerVersion();
+
+ // Check `collation_connection` for each one of the known character sets.
+ this.rs = this.stmt.executeQuery("SELECT character_set_name FROM information_schema.character_sets");
+ int csCount = 0;
+ while (this.rs.next()) {
+ csCount++;
+ String cs = this.rs.getString(1);
+
+ // The following cannot be set as client_character_set
+ // (https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html#charset-connection-impermissible-client-charset)
+ if (cs.equalsIgnoreCase("ucs2") || cs.equalsIgnoreCase("utf16") || cs.equalsIgnoreCase("utf16le") || cs.equalsIgnoreCase("utf32")) {
+ continue;
+ }
+
+ String javaEnc = ((MysqlConnection) c).getSession().getServerSession().getCharsetSettings().getJavaEncodingForMysqlCharset(cs);
+ System.out.println(cs + "->" + javaEnc);
+ String charsetForJavaEnc = ((MysqlConnection) c).getSession().getServerSession().getCharsetSettings().getMysqlCharsetForJavaEncoding(javaEnc, sv);
+ String expectedCollation = defaultCollations.get(charsetForJavaEnc);
+
+ if ("UTF-8".equalsIgnoreCase(javaEnc)) {
+ // UTF-8 is the exception. This encoding is converted to MySQL charset 'utf8mb4' instead of 'utf8', and its corresponding collation.
+ expectedCollation = versionMeetsMinimum(8, 0, 1) ? "utf8mb4_0900_ai_ci" : "utf8mb4_general_ci";
+ }
+
+ Properties p2 = new Properties();
+ p2.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ p2.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ p2.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true");
+ p2.setProperty(PropertyKey.customCharsetMapping.getKeyName(), "custom:Cp1252");
+ p2.setProperty(PropertyKey.characterEncoding.getKeyName(), javaEnc);
+
+ Connection testConn = getConnectionWithProps(p2);
+ ResultSet testRs = testConn.createStatement().executeQuery("SHOW VARIABLES LIKE 'collation_connection'");
+ assertTrue(testRs.next());
+ assertEquals(expectedCollation, testRs.getString(2));
+ testConn.close();
+ }
+ // Assert that some charsets were tested.
+ assertTrue(csCount > 35); // There are 39 charsets in MySQL 5.5.61, 40 in MySQL 5.6.41 and 41 in MySQL 5.7.23 and above, but these numbers can vary.
+ }
+
+ /**
+ * Test for Bug#72712 - SET NAMES issued unnecessarily.
+ *
+ * Using a statement interceptor, ensure that SET NAMES is not called if the encoding requested by the client application matches that of
+ * character_set_server.
+ *
+ * Also test that character_set_results is not set unnecessarily.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug72712() throws Exception {
+ assumeTrue(((MysqlConnection) this.conn).getSession().getServerSession().getServerVariable("character_set_server").equals("latin1"),
+ "This test only run when character_set_server=latin1");
+
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ p.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "cp1252");
+ p.setProperty(PropertyKey.characterSetResults.getKeyName(), "cp1252");
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug72712QueryInterceptor.class.getName());
+
+ getConnectionWithProps(p);
+ // exception will be thrown from the statement interceptor if any SET statements are issued
+ }
+
+ /**
+ * Statement interceptor used to implement preceding test.
+ */
+ public static class Bug72712QueryInterceptor extends BaseQueryInterceptor {
+ @Override
+ public T preProcess(Supplier str, Query interceptedQuery) {
+ String sql = str.get();
+ if (sql.contains("SET NAMES")
+ || sql.contains(CharsetSettings.CHARACTER_SET_RESULTS) && !(sql.contains("SHOW VARIABLES") || sql.contains("SELECT @@"))) {
+ throw ExceptionFactory.createException("Wrongt statement issued: " + sql);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Tests fix for Bug#95139 (29807572), CACHESERVERCONFIGURATION APPEARS TO THWART CHARSET DETECTION.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBug95139() throws Exception {
+
+ Properties p = new Properties();
+ p.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ p.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug95139QueryInterceptor.class.getName());
+ testBug95139CheckVariables(p, 1, null, "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL");
+
+ p.setProperty(PropertyKey.cacheServerConfiguration.getKeyName(), "true");
+ p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true");
+
+ // Empty the cache possibly created by other tests to get a correct queryVarsCnt on the next step
+ Connection c = getConnectionWithProps(p);
+ Field f = NativeSession.class.getDeclaredField("serverConfigCache");
+ f.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ CacheAdapter> cache = (CacheAdapter>) f.get(((MysqlConnection) c).getSession());
+ if (cache != null) {
+ cache.invalidateAll();
+ }
+
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "cp1252");
+ p.setProperty(PropertyKey.characterSetResults.getKeyName(), "cp1252");
+ testBug95139CheckVariables(p, 1, null, null);
+
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ p.setProperty(PropertyKey.characterSetResults.getKeyName(), "cp1252");
+ testBug95139CheckVariables(p, 0, null, "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = latin1");
+
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ p.remove(PropertyKey.characterSetResults.getKeyName());
+ testBug95139CheckVariables(p, 0, null, "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL");
+
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ p.setProperty(PropertyKey.passwordCharacterEncoding.getKeyName(), "latin1");
+ testBug95139CheckVariables(p, 0, "SET NAMES utf8mb4", "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL");
+
+ p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
+ p.setProperty(PropertyKey.passwordCharacterEncoding.getKeyName(), "latin1");
+ p.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8mb4_bin");
+ testBug95139CheckVariables(p, 0, "SET NAMES utf8mb4 COLLATE utf8mb4_bin", "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL");
+ }
+
+ private void testBug95139CheckVariables(Properties p, int queryVarsCnt, String expSetNamesQuery, String expSetCharacterSetResultsquery) throws Exception {
+ Connection con = getConnectionWithProps(p);
+
+ Bug95139QueryInterceptor si = (Bug95139QueryInterceptor) ((JdbcConnection) con).getQueryInterceptorsInstances().get(0);
+ assertEquals(queryVarsCnt, si.queryVarsCnt);
+ assertEquals(expSetNamesQuery == null ? 0 : 1, si.setNamesCnt);
+ assertEquals(expSetCharacterSetResultsquery == null ? 0 : 1, si.setCharacterSetResultsCnt);
+ if (expSetNamesQuery != null) {
+ assertEquals(expSetNamesQuery, si.setNamesQuery);
+ }
+ if (expSetCharacterSetResultsquery != null) {
+ assertEquals(expSetCharacterSetResultsquery, si.setCharacterSetResultsQuery);
+ }
+
+ Map svs = ((MysqlConnection) con).getSession().getServerSession().getServerVariables();
+ System.out.println(svs);
+ Map exp = new HashMap<>();
+ exp.put("character_set_client", svs.get("character_set_client"));
+ exp.put("character_set_connection", svs.get("character_set_connection"));
+ exp.put("character_set_results", svs.get("character_set_results") == null ? "" : svs.get("character_set_results"));
+ exp.put("character_set_server", svs.get("character_set_server"));
+ exp.put("collation_server", svs.get("collation_server"));
+ exp.put("collation_connection", svs.get("collation_connection"));
+
+ ResultSet rset = con.createStatement()
+ .executeQuery("show variables where variable_name='character_set_client' or variable_name='character_set_connection'"
+ + " or variable_name='character_set_results' or variable_name='character_set_server' or variable_name='collation_server'"
+ + " or variable_name='collation_connection'");
+ while (rset.next()) {
+ System.out.println(rset.getString(1) + "=" + rset.getString(2));
+ assertEquals(exp.get(rset.getString(1)), rset.getString(2), rset.getString(1));
+ }
+
+ con.close();
+ }
+
+ public static class Bug95139QueryInterceptor extends BaseQueryInterceptor {
+ int queryVarsCnt = 0;
+ int setNamesCnt = 0;
+ String setNamesQuery = null;
+ int setCharacterSetResultsCnt = 0;
+ String setCharacterSetResultsQuery = null;
+
+ @Override
+ public M preProcess(M queryPacket) {
+ String sql = StringUtils.toString(queryPacket.getByteBuffer(), 0, queryPacket.getPosition());
+ if (sql.contains("SET NAMES")) {
+ this.setNamesCnt++;
+ this.setNamesQuery = sql.substring(sql.indexOf("SET"));
+ } else if (sql.contains("SET " + CharsetSettings.CHARACTER_SET_RESULTS)) {
+ this.setCharacterSetResultsCnt++;
+ this.setCharacterSetResultsQuery = sql.substring(sql.indexOf("SET"));
+ } else if (sql.contains("SHOW VARIABLES") || sql.contains("SELECT @@")) {
+ System.out.println(sql.substring(sql.indexOf("S")));
+ this.queryVarsCnt++;
+ }
+ return null;
+ }
+
+ @Override
+ public T preProcess(Supplier str, Query interceptedQuery) {
+ String sql = str.get();
+ if (sql.contains("SET NAMES")) {
+ this.setNamesCnt++;
+ } else if (sql.contains("SET " + CharsetSettings.CHARACTER_SET_RESULTS)) {
+ this.setCharacterSetResultsCnt++;
+ } else if (sql.contains("SHOW VARIABLES") || sql.contains("SELECT @@")) {
+ System.out.println(sql.substring(sql.indexOf("S")));
+ this.queryVarsCnt++;
+ }
+ return null;
+ }
+ }
+
}
diff --git a/src/test/java/testsuite/regression/ConnectionRegressionTest.java b/src/test/java/testsuite/regression/ConnectionRegressionTest.java
index dac614df2..14ca22d8d 100644
--- a/src/test/java/testsuite/regression/ConnectionRegressionTest.java
+++ b/src/test/java/testsuite/regression/ConnectionRegressionTest.java
@@ -31,6 +31,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -87,7 +88,6 @@
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
@@ -118,9 +118,11 @@
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import com.mysql.cj.CharsetMapping;
+import com.mysql.cj.CharsetMappingWrapper;
+import com.mysql.cj.CharsetSettings;
import com.mysql.cj.Constants;
import com.mysql.cj.Messages;
import com.mysql.cj.MysqlConnection;
@@ -146,7 +148,9 @@
import com.mysql.cj.exceptions.PropertyNotModifiableException;
import com.mysql.cj.interceptors.QueryInterceptor;
import com.mysql.cj.jdbc.ClientInfoProvider;
+import com.mysql.cj.jdbc.ClientInfoProviderSP;
import com.mysql.cj.jdbc.ClientPreparedStatement;
+import com.mysql.cj.jdbc.CommentClientInfoProvider;
import com.mysql.cj.jdbc.ConnectionGroupManager;
import com.mysql.cj.jdbc.ConnectionImpl;
import com.mysql.cj.jdbc.JdbcConnection;
@@ -184,6 +188,10 @@
import com.mysql.cj.protocol.PacketSentTimeHolder;
import com.mysql.cj.protocol.Resultset;
import com.mysql.cj.protocol.ServerSession;
+import com.mysql.cj.protocol.ServerSessionStateController;
+import com.mysql.cj.protocol.ServerSessionStateController.ServerSessionStateChanges;
+import com.mysql.cj.protocol.ServerSessionStateController.SessionStateChange;
+import com.mysql.cj.protocol.ServerSessionStateController.SessionStateChangesListener;
import com.mysql.cj.protocol.StandardSocketFactory;
import com.mysql.cj.protocol.a.DebugBufferingPacketReader;
import com.mysql.cj.protocol.a.DebugBufferingPacketSender;
@@ -260,6 +268,8 @@ public void testBug3790() throws Exception {
ResultSet rs2 = null;
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
try {
createTable("testBug3790", "(field1 INT NOT NULL PRIMARY KEY, field2 VARCHAR(32)) ", "InnoDB");
@@ -305,71 +315,6 @@ public void testBug3790() throws Exception {
}
}
- /**
- * Tests if the driver configures character sets correctly for 4.1.x servers. Requires that the 'admin connection' is configured, as this test needs to
- * create/drop databases.
- *
- * @throws Exception
- */
- @Test
- public void testCollation41() throws Exception {
- if (isAdminConnectionConfigured()) {
- Map charsetsAndCollations = getCharacterSetsAndCollations();
- charsetsAndCollations.remove("latin7"); // Maps to multiple Java
- // charsets
- charsetsAndCollations.remove("ucs2"); // can't be used as a
- // connection charset
-
- for (String charsetName : charsetsAndCollations.keySet()) {
- Connection charsetConn = null;
- Statement charsetStmt = null;
-
- try {
- //String collationName = charsetsAndCollations.get(charsetName);
-
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), charsetName);
-
- System.out.println("Testing character set " + charsetName);
-
- charsetConn = getAdminConnectionWithProps(props);
-
- charsetStmt = charsetConn.createStatement();
-
- charsetStmt.executeUpdate("DROP DATABASE IF EXISTS testCollation41");
- charsetStmt.executeUpdate("DROP TABLE IF EXISTS testCollation41");
- charsetStmt.executeUpdate("CREATE DATABASE testCollation41 DEFAULT CHARACTER SET " + charsetName);
- charsetStmt.close();
-
- charsetConn.setCatalog("testCollation41");
-
- // We've switched catalogs, so we need to recreate the
- // statement to pick this up...
- charsetStmt = charsetConn.createStatement();
-
- StringBuilder createTableCommand = new StringBuilder("CREATE TABLE testCollation41(field1 VARCHAR(255), field2 INT)");
-
- charsetStmt.executeUpdate(createTableCommand.toString());
-
- charsetStmt.executeUpdate("INSERT INTO testCollation41 VALUES ('abc', 0)");
-
- int updateCount = charsetStmt.executeUpdate("UPDATE testCollation41 SET field2=1 WHERE field1='abc'");
- assertTrue(updateCount == 1);
- } finally {
- if (charsetStmt != null) {
- charsetStmt.executeUpdate("DROP TABLE IF EXISTS testCollation41");
- charsetStmt.executeUpdate("DROP DATABASE IF EXISTS testCollation41");
- charsetStmt.close();
- }
-
- if (charsetConn != null) {
- charsetConn.close();
- }
- }
- }
- }
- }
-
/**
* Tests setReadOnly() being reset during failover
*
@@ -378,6 +323,8 @@ public void testCollation41() throws Exception {
@Test
public void testSetReadOnly() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
String sepChar = "?";
@@ -397,7 +344,10 @@ public void testSetReadOnly() throws Exception {
boolean isReadOnly = reconnectableConn.isReadOnly();
- Connection killConn = getConnectionWithProps((Properties) null);
+ Properties props2 = new Properties();
+ props2.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props2.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ Connection killConn = getConnectionWithProps(props2);
killConn.createStatement().executeUpdate("KILL " + connectionId);
Thread.sleep(2000);
@@ -433,35 +383,6 @@ public void testSetReadOnly() throws Exception {
assertTrue(reconnectableConn.isReadOnly() == isReadOnly);
}
- private Map getCharacterSetsAndCollations() throws Exception {
- Map charsetsToLoad = new HashMap<>();
-
- try {
- this.rs = this.stmt.executeQuery("SHOW character set");
-
- while (this.rs.next()) {
- charsetsToLoad.put(this.rs.getString("Charset"), this.rs.getString("Default collation"));
- }
-
- //
- // These don't have mappings in Java...
- //
- charsetsToLoad.remove("swe7");
- charsetsToLoad.remove("hp8");
- charsetsToLoad.remove("dec8");
- charsetsToLoad.remove("koi8u");
- charsetsToLoad.remove("keybcs2");
- charsetsToLoad.remove("geostd8");
- charsetsToLoad.remove("armscii8");
- } finally {
- if (this.rs != null) {
- this.rs.close();
- }
- }
-
- return charsetsToLoad;
- }
-
/**
* Tests fix for BUG#4334, port #'s not being picked up for failover/autoreconnect.
*
@@ -469,144 +390,147 @@ private Map getCharacterSetsAndCollations() throws Exception {
*/
@Test
public void testBug4334() throws Exception {
- if (isAdminConnectionConfigured()) {
- Connection adminConnection = null;
-
- try {
- adminConnection = getAdminConnection();
+ Connection adminConnection = null;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- int bogusPortNumber = 65534;
+ try {
+ adminConnection = getConnectionWithProps(props);
- HostInfo defaultHost = mainConnectionUrl.getMainHost();
+ int bogusPortNumber = 65534;
- String host = defaultHost.getHost();
- int port = defaultHost.getPort();
- String database = defaultHost.getDatabase();
- String user = defaultHost.getUser();
- String password = defaultHost.getPassword();
+ HostInfo defaultHost = mainConnectionUrl.getMainHost();
- StringBuilder newUrlToTestPortNum = new StringBuilder("jdbc:mysql://");
+ String host = defaultHost.getHost();
+ int port = defaultHost.getPort();
+ String database = defaultHost.getDatabase();
+ String user = defaultHost.getUser();
+ String password = defaultHost.getPassword();
- if (host != null) {
- newUrlToTestPortNum.append(host);
- }
+ StringBuilder newUrlToTestPortNum = new StringBuilder("jdbc:mysql://");
- newUrlToTestPortNum.append(":").append(port);
- newUrlToTestPortNum.append(",");
+ if (host != null) {
+ newUrlToTestPortNum.append(host);
+ }
- if (host != null) {
- newUrlToTestPortNum.append(host);
- }
+ newUrlToTestPortNum.append(":").append(port);
+ newUrlToTestPortNum.append(",");
- newUrlToTestPortNum.append(":").append(bogusPortNumber);
- newUrlToTestPortNum.append("/");
+ if (host != null) {
+ newUrlToTestPortNum.append(host);
+ }
- if (database != null) {
- newUrlToTestPortNum.append(database);
- }
+ newUrlToTestPortNum.append(":").append(bogusPortNumber);
+ newUrlToTestPortNum.append("/");
- if ((user != null) || (password != null)) {
- newUrlToTestPortNum.append("?");
+ if (database != null) {
+ newUrlToTestPortNum.append(database);
+ }
- if (user != null) {
- newUrlToTestPortNum.append("user=").append(user);
+ if ((user != null) || (password != null)) {
+ newUrlToTestPortNum.append("?");
- if (password != null) {
- newUrlToTestPortNum.append("&");
- }
- }
+ if (user != null) {
+ newUrlToTestPortNum.append("user=").append(user);
if (password != null) {
- newUrlToTestPortNum.append("password=").append(password);
+ newUrlToTestPortNum.append("&");
}
}
- Properties autoReconnectProps = new Properties();
- autoReconnectProps.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
+ if (password != null) {
+ newUrlToTestPortNum.append("password=").append(password);
+ }
+ }
- System.out.println(newUrlToTestPortNum);
+ Properties autoReconnectProps = new Properties();
+ autoReconnectProps.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ autoReconnectProps.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ autoReconnectProps.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
- //
- // First test that port #'s are being correctly picked up
- //
- // We do this by looking at the error message that is returned
- //
- Connection portNumConn = DriverManager.getConnection(newUrlToTestPortNum.toString(), autoReconnectProps);
- Statement portNumStmt = portNumConn.createStatement();
- this.rs = portNumStmt.executeQuery("SELECT connection_id()");
- this.rs.next();
+ System.out.println(newUrlToTestPortNum);
- killConnection(adminConnection, this.rs.getString(1));
+ //
+ // First test that port #'s are being correctly picked up
+ //
+ // We do this by looking at the error message that is returned
+ //
+ Connection portNumConn = DriverManager.getConnection(newUrlToTestPortNum.toString(), autoReconnectProps);
+ Statement portNumStmt = portNumConn.createStatement();
+ this.rs = portNumStmt.executeQuery("SELECT connection_id()");
+ this.rs.next();
- try {
- portNumStmt.executeQuery("SELECT connection_id()");
- } catch (SQLException sqlEx) {
- // we expect this one
- }
+ killConnection(adminConnection, this.rs.getString(1));
- try {
- portNumStmt.executeQuery("SELECT connection_id()");
- } catch (SQLException sqlEx) {
- assertTrue(sqlEx.getMessage().toLowerCase().indexOf("connection refused") != -1);
- }
+ try {
+ portNumStmt.executeQuery("SELECT connection_id()");
+ } catch (SQLException sqlEx) {
+ // we expect this one
+ }
- //
- // Now make sure failover works
- //
- StringBuilder newUrlToTestFailover = new StringBuilder("jdbc:mysql://");
+ try {
+ portNumStmt.executeQuery("SELECT connection_id()");
+ } catch (SQLException sqlEx) {
+ assertTrue(sqlEx.getMessage().toLowerCase().indexOf("connection refused") != -1);
+ }
- if (host != null) {
- newUrlToTestFailover.append(host);
- }
+ //
+ // Now make sure failover works
+ //
+ StringBuilder newUrlToTestFailover = new StringBuilder("jdbc:mysql://");
- newUrlToTestFailover.append(":").append(port);
- newUrlToTestFailover.append(",");
+ if (host != null) {
+ newUrlToTestFailover.append(host);
+ }
- if (host != null) {
- newUrlToTestFailover.append(host);
- }
+ newUrlToTestFailover.append(":").append(port);
+ newUrlToTestFailover.append(",");
- newUrlToTestFailover.append(":").append(bogusPortNumber);
- newUrlToTestFailover.append("/");
+ if (host != null) {
+ newUrlToTestFailover.append(host);
+ }
- if (database != null) {
- newUrlToTestFailover.append(database);
- }
+ newUrlToTestFailover.append(":").append(bogusPortNumber);
+ newUrlToTestFailover.append("/");
- if ((user != null) || (password != null)) {
- newUrlToTestFailover.append("?");
+ if (database != null) {
+ newUrlToTestFailover.append(database);
+ }
- if (user != null) {
- newUrlToTestFailover.append("user=").append(user);
+ if ((user != null) || (password != null)) {
+ newUrlToTestFailover.append("?");
- if (password != null) {
- newUrlToTestFailover.append("&");
- }
- }
+ if (user != null) {
+ newUrlToTestFailover.append("user=").append(user);
if (password != null) {
- newUrlToTestFailover.append("password=").append(password);
+ newUrlToTestFailover.append("&");
}
}
- Connection failoverConn = DriverManager.getConnection(newUrlToTestFailover.toString(), autoReconnectProps);
- Statement failoverStmt = failoverConn.createStatement();
- this.rs = failoverStmt.executeQuery("SELECT connection_id()");
- this.rs.next();
+ if (password != null) {
+ newUrlToTestFailover.append("password=").append(password);
+ }
+ }
- killConnection(adminConnection, this.rs.getString(1));
+ Connection failoverConn = DriverManager.getConnection(newUrlToTestFailover.toString(), autoReconnectProps);
+ Statement failoverStmt = failoverConn.createStatement();
+ this.rs = failoverStmt.executeQuery("SELECT connection_id()");
+ this.rs.next();
- try {
- failoverStmt.executeQuery("SELECT connection_id()");
- } catch (SQLException sqlEx) {
- // we expect this one
- }
+ killConnection(adminConnection, this.rs.getString(1));
- this.rs = failoverStmt.executeQuery("SELECT connection_id()");
- } finally {
- if (adminConnection != null) {
- adminConnection.close();
- }
+ try {
+ failoverStmt.executeQuery("SELECT connection_id()");
+ } catch (SQLException sqlEx) {
+ // we expect this one
+ }
+
+ this.rs = failoverStmt.executeQuery("SELECT connection_id()");
+ } finally {
+ if (adminConnection != null) {
+ adminConnection.close();
}
}
}
@@ -624,6 +548,8 @@ private static void killConnection(Connection adminConn, String threadId) throws
@Test
public void testBug6966() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.socketFactory.getKeyName(), "testsuite.UnreliableSocketFactory");
@@ -679,12 +605,16 @@ public void testBug6966() throws Exception {
public void testBug7952() throws Exception {
String host = getEncodedHostPortPairFromTestsuiteUrl() + "," + getEncodedHostPortPairFromTestsuiteUrl();
Properties props = getHostFreePropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
+ Connection killerConnection = getConnectionWithProps(props);
+
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.queriesBeforeRetrySource.getKeyName(), "10");
props.setProperty(PropertyKey.maxReconnects.getKeyName(), "1");
Connection failoverConnection = null;
- Connection killerConnection = getConnectionWithProps((String) null);
try {
failoverConnection = getConnectionWithProps("jdbc:mysql://" + host + "/", props);
@@ -743,150 +673,6 @@ public void testBug7952() throws Exception {
}
}
- /**
- * Tests fix for BUG#7607 - MS932, SHIFT_JIS and Windows_31J not recog. as aliases for sjis.
- *
- * @throws Exception
- */
- @Test
- public void testBug7607() throws Exception {
- Connection ms932Conn = null, cp943Conn = null, shiftJisConn = null, windows31JConn = null;
-
- try {
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "MS932");
-
- ms932Conn = getConnectionWithProps(props);
-
- this.rs = ms932Conn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
- assertTrue(this.rs.next());
- String encoding = this.rs.getString(2);
- assertEquals("cp932", encoding.toLowerCase(Locale.ENGLISH));
-
- this.rs = ms932Conn.createStatement().executeQuery("SELECT 'abc'");
- assertTrue(this.rs.next());
-
- String charsetToCheck = "ms932";
-
- assertEquals(charsetToCheck,
- ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toLowerCase(Locale.ENGLISH));
-
- try {
- ms932Conn.createStatement().executeUpdate("drop table if exists testBug7607");
- ms932Conn.createStatement().executeUpdate("create table testBug7607 (sortCol int, col1 varchar(100) ) character set sjis");
- ms932Conn.createStatement().executeUpdate("insert into testBug7607 values(1, 0x835C)"); // standard
- // sjis
- ms932Conn.createStatement().executeUpdate("insert into testBug7607 values(2, 0x878A)"); // NEC
- // kanji
-
- this.rs = ms932Conn.createStatement().executeQuery("SELECT col1 FROM testBug7607 ORDER BY sortCol ASC");
- assertTrue(this.rs.next());
- String asString = this.rs.getString(1);
- assertTrue("\u30bd".equals(asString));
-
- assertTrue(this.rs.next());
- asString = this.rs.getString(1);
- assertEquals("\u3231", asString);
- } finally {
- ms932Conn.createStatement().executeUpdate("drop table if exists testBug7607");
- }
-
- props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "SHIFT_JIS");
-
- shiftJisConn = getConnectionWithProps(props);
-
- this.rs = shiftJisConn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
- assertTrue(this.rs.next());
- encoding = this.rs.getString(2);
- assertTrue("sjis".equalsIgnoreCase(encoding));
-
- this.rs = shiftJisConn.createStatement().executeQuery("SELECT 'abc'");
- assertTrue(this.rs.next());
-
- String charSetUC = ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toUpperCase(Locale.US);
-
- props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "WINDOWS-31J");
-
- windows31JConn = getConnectionWithProps(props);
-
- this.rs = windows31JConn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
- assertTrue(this.rs.next());
- encoding = this.rs.getString(2);
-
- assertEquals("cp932", encoding.toLowerCase(Locale.ENGLISH));
-
- this.rs = windows31JConn.createStatement().executeQuery("SELECT 'abc'");
- assertTrue(this.rs.next());
-
- assertEquals("windows-31j".toLowerCase(Locale.ENGLISH),
- ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toLowerCase(Locale.ENGLISH));
-
- props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "CP943");
-
- cp943Conn = getConnectionWithProps(props);
-
- this.rs = cp943Conn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_set_client'");
- assertTrue(this.rs.next());
- encoding = this.rs.getString(2);
- assertTrue("sjis".equalsIgnoreCase(encoding));
-
- this.rs = cp943Conn.createStatement().executeQuery("SELECT 'abc'");
- assertTrue(this.rs.next());
-
- charSetUC = ((com.mysql.cj.jdbc.result.ResultSetMetaData) this.rs.getMetaData()).getColumnCharacterEncoding(1).toUpperCase(Locale.US);
-
- assertEquals("CP943", charSetUC);
-
- } finally {
- if (ms932Conn != null) {
- ms932Conn.close();
- }
-
- if (shiftJisConn != null) {
- shiftJisConn.close();
- }
-
- if (windows31JConn != null) {
- windows31JConn.close();
- }
-
- if (cp943Conn != null) {
- cp943Conn.close();
- }
- }
- }
-
- /**
- * Tests fix for BUG#9206, can not use 'UTF-8' for characterSetResults configuration property.
- *
- * @throws Exception
- */
- @Test
- public void testBug9206() throws Exception {
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "UTF-8");
- getConnectionWithProps(props).close();
- }
-
- /**
- * These two charsets have different names depending on version of MySQL server.
- *
- * @throws Exception
- */
- @Test
- public void testNewCharsetsConfiguration() throws Exception {
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "EUC_KR");
- getConnectionWithProps(props).close();
-
- props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "KOI8_R");
- getConnectionWithProps(props).close();
- }
-
/**
* Tests fix for BUG#10144 - Memory leak in ServerPreparedStatement if serverPrepare() fails.
*
@@ -895,6 +681,8 @@ public void testNewCharsetsConfiguration() throws Exception {
@Test
public void testBug10144() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.emulateUnsupportedPstmts.getKeyName(), "false");
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "true");
@@ -912,24 +700,6 @@ public void testBug10144() throws Exception {
}
}
- /**
- * Tests fix for BUG#10496 - SQLException is thrown when using property "characterSetResults"
- *
- * @throws Exception
- */
- @Test
- public void testBug10496() throws Exception {
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "WINDOWS-31J");
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "WINDOWS-31J");
- getConnectionWithProps(props).close();
-
- props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "EUC_JP");
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "EUC_JP");
- getConnectionWithProps(props).close();
- }
-
/**
* Tests fix for BUG#11259, autoReconnect ping causes exception on connection startup.
*
@@ -940,6 +710,8 @@ public void testBug11259() throws Exception {
Connection dsConn = null;
try {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
dsConn = getConnectionWithProps(props);
} finally {
@@ -956,17 +728,17 @@ public void testBug11259() throws Exception {
*/
@Test
public void testBug11879() throws Exception {
- if (runMultiHostTests()) {
- Connection replConn = null;
-
- try {
- replConn = getSourceReplicaReplicationConnection();
- replConn.setReadOnly(true);
- replConn.setReadOnly(false);
- } finally {
- if (replConn != null) {
- replConn.close();
- }
+ Connection replConn = null;
+ try {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ replConn = getSourceReplicaReplicationConnection(props);
+ replConn.setReadOnly(true);
+ replConn.setReadOnly(false);
+ } finally {
+ if (replConn != null) {
+ replConn.close();
}
}
}
@@ -979,6 +751,8 @@ public void testBug11879() throws Exception {
@Test
public void testBug11976() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useConfigs.getKeyName(), "maxPerformance");
Connection maxPerfConn = getConnectionWithProps(props);
@@ -992,26 +766,25 @@ public void testBug11976() throws Exception {
*/
@Test
public void testBug12218() throws Exception {
- if (runMultiHostTests()) {
- Connection replConn = null;
+ Connection replConn = null;
- HostInfo hostInfo = mainConnectionUrl.getMainHost();
- Properties props = new Properties();
- props.setProperty(PropertyKey.USER.getKeyName(), hostInfo.getUser() == null ? "" : hostInfo.getUser());
- props.setProperty(PropertyKey.PASSWORD.getKeyName(), hostInfo.getPassword() == null ? "" : hostInfo.getPassword());
- props = appendRequiredProperties(props);
+ HostInfo hostInfo = mainConnectionUrl.getMainHost();
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.USER.getKeyName(), hostInfo.getUser() == null ? "" : hostInfo.getUser());
+ props.setProperty(PropertyKey.PASSWORD.getKeyName(), hostInfo.getPassword() == null ? "" : hostInfo.getPassword());
+ props = appendRequiredProperties(props);
- String replUrl = String.format("%1$s//address=(host=%2$s)(port=%3$d),address=(host=%2$s)(port=%3$d)(isReplica=true)/%4$s",
- ConnectionUrl.Type.REPLICATION_CONNECTION.getScheme(), getEncodedHostFromTestsuiteUrl(), getPortFromTestsuiteUrl(), hostInfo.getDatabase());
+ String replUrl = String.format("%1$s//address=(host=%2$s)(port=%3$d),address=(host=%2$s)(port=%3$d)(isReplica=true)/%4$s",
+ ConnectionUrl.Type.REPLICATION_CONNECTION.getScheme(), getEncodedHostFromTestsuiteUrl(), getPortFromTestsuiteUrl(), hostInfo.getDatabase());
- try {
- replConn = DriverManager.getConnection(replUrl, props);
- assertTrue(
- !((ReplicationConnection) replConn).getSourceConnection().hasSameProperties(((ReplicationConnection) replConn).getReplicaConnection()));
- } finally {
- if (replConn != null) {
- replConn.close();
- }
+ try {
+ replConn = DriverManager.getConnection(replUrl, props);
+ assertTrue(!((ReplicationConnection) replConn).getSourceConnection().hasSameProperties(((ReplicationConnection) replConn).getReplicaConnection()));
+ } finally {
+ if (replConn != null) {
+ replConn.close();
}
}
}
@@ -1027,6 +800,8 @@ public void testBug12229() throws Exception {
this.stmt.executeUpdate("insert into testBug12229 values (123456),(1)");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
props.setProperty(PropertyKey.slowQueryThresholdMillis.getKeyName(), "0");
props.setProperty(PropertyKey.logSlowQueries.getKeyName(), "true");
@@ -1048,18 +823,6 @@ public void testBug12229() throws Exception {
assertTrue(this.rs.next());
}
- /**
- * Tests fix for BUG#12752 - Cp1251 incorrectly mapped to win1251 for servers newer than 4.0.x.
- *
- * @throws Exception
- */
- @Test
- public void testBug12752() throws Exception {
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "Cp1251");
- getConnectionWithProps(props).close();
- }
-
/**
* Tests fix for BUG#12753, sessionVariables=....=...., doesn't work as it's tokenized incorrectly.
*
@@ -1068,6 +831,8 @@ public void testBug12752() throws Exception {
@Test
public void testBug12753() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.sessionVariables.getKeyName(), "sql_mode=ansi");
Connection sessionConn = null;
@@ -1100,6 +865,8 @@ public void testBug13048() throws Exception {
System.setErr(new PrintStream(bOut));
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
props.setProperty(PropertyKey.maxQuerySizeToLog.getKeyName(), "2");
props.setProperty(PropertyKey.logger.getKeyName(), StandardLogger.class.getName());
@@ -1162,7 +929,10 @@ public void testBug13453() throws Exception {
Connection encodedConn = null;
try {
- encodedConn = DriverManager.getConnection(urlBuf.toString(), null);
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ encodedConn = DriverManager.getConnection(urlBuf.toString(), props);
this.rs = encodedConn.createStatement().executeQuery("SELECT @testBug13453");
assertTrue(this.rs.next());
@@ -1195,6 +965,8 @@ public void testBug15065() throws Exception {
try {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useUsageAdvisor.getKeyName(), "true");
props.setProperty(PropertyKey.logger.getKeyName(), StandardLogger.class.getName());
@@ -1282,53 +1054,6 @@ public void testBug15065() throws Exception {
}
}
- /**
- * Tests fix for BUG#15544, no "dos" character set in MySQL > 4.1.0
- *
- * @throws Exception
- */
- @Test
- public void testBug15544() throws Exception {
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "Cp437");
- Connection dosConn = null;
-
- try {
- dosConn = getConnectionWithProps(props);
- } finally {
- if (dosConn != null) {
- dosConn.close();
- }
- }
- }
-
- @Test
- public void testCSC5765() throws Exception {
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "utf8");
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "utf8");
- props.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8_bin");
-
- Connection utf8Conn = null;
-
- try {
- utf8Conn = getConnectionWithProps(props);
- this.rs = utf8Conn.createStatement().executeQuery("SHOW VARIABLES LIKE 'character_%'");
- while (this.rs.next()) {
- System.out.println(this.rs.getString(1) + " = " + this.rs.getString(2));
- }
-
- this.rs = utf8Conn.createStatement().executeQuery("SHOW VARIABLES LIKE 'collation_%'");
- while (this.rs.next()) {
- System.out.println(this.rs.getString(1) + " = " + this.rs.getString(2));
- }
- } finally {
- if (utf8Conn != null) {
- utf8Conn.close();
- }
- }
- }
-
/**
* Tests fix for BUG#15570 - ReplicationConnection incorrectly copies state, doesn't transfer connection context correctly when transitioning between the
* same read-only states.
@@ -1342,7 +1067,10 @@ public void testBug15570() throws Exception {
Connection replConn = null;
try {
- replConn = getSourceReplicaReplicationConnection();
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ replConn = getSourceReplicaReplicationConnection(props);
boolean dbMapsToSchema = ((JdbcConnection) replConn).getPropertySet().getEnumProperty(PropertyKey.databaseTerm)
.getValue() == DatabaseTerm.SCHEMA;
@@ -1403,6 +1131,8 @@ public void testBug15570() throws Exception {
@Test
public void testBug23281() throws Exception {
Properties props = getHostFreePropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "false");
props.setProperty(PropertyKey.failOverReadOnly.getKeyName(), "false");
props.setProperty(PropertyKey.connectTimeout.getKeyName(), "5000");
@@ -1448,14 +1178,8 @@ public void testBug23281() throws Exception {
* @throws Exception
*/
@Test
+ @Disabled("'elideSetAutoCommits' feature was turned off due to Server Bug#66884. Turn this test back on as soon as the server bug is fixed. Consider making it version specific.")
public void testBug24706() throws Exception {
- // '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();
props.setProperty(PropertyKey.elideSetAutoCommits.getKeyName(), "true");
props.setProperty(PropertyKey.logger.getKeyName(), BufferingLogger.class.getName());
@@ -1503,8 +1227,11 @@ public void testBug24706() throws Exception {
*/
@Test
public void testBug25514() throws Exception {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
for (int i = 0; i < 10; i++) {
- getConnectionWithProps((Properties) null).close();
+ getConnectionWithProps(props).close();
}
ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();
@@ -1658,6 +1385,13 @@ private void testBug23626ForClass(Class> clazz, List propertyNames) th
*/
@Test
public void testBug25545() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
createProcedure("testBug25545", "() BEGIN SELECT 1; END");
String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
@@ -1671,8 +1405,7 @@ public void testBug25545() throws Exception {
try {
Properties props = new Properties();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
sslConn = getConnectionWithProps(props);
sslConn.prepareCall("{ call testBug25545()}").execute();
@@ -1692,12 +1425,20 @@ public void testBug25545() throws Exception {
*/
@Test
public void testBug36948() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
Connection _conn = null;
try {
String hostSpec = getEncodedHostPortPairFromTestsuiteUrl();
Properties props = getHostFreePropertiesFromTestsuiteUrl();
String db = props.getProperty(PropertyKey.DBNAME.getKeyName(), "test");
+ props.remove(PropertyKey.sslMode.getKeyName());
props.remove(PropertyKey.useSSL.getKeyName());
props.remove(PropertyKey.requireSSL.getKeyName());
props.remove(PropertyKey.verifyServerCertificate.getKeyName());
@@ -1705,7 +1446,7 @@ public void testBug36948() throws Exception {
props.remove(PropertyKey.trustCertificateKeyStoreType.getKeyName());
props.remove(PropertyKey.trustCertificateKeyStorePassword.getKeyName());
- final String url = "jdbc:mysql://" + hostSpec + "/" + db + "?useSSL=true&requireSSL=true&verifyServerCertificate=true"
+ final String url = "jdbc:mysql://" + hostSpec + "/" + db + "?sslMode=REQUIRED&verifyServerCertificate=true"
+ "&trustCertificateKeyStoreUrl=file:src/test/config/ssl-test-certs/ca-truststore&trustCertificateKeyStoreType=JKS"
+ "&trustCertificateKeyStorePassword=password";
@@ -1725,6 +1466,8 @@ public void testBug36948() throws Exception {
@Test
public void testBug27655() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
props.setProperty(PropertyKey.logger.getKeyName(), BufferingLogger.class.getName());
BufferingLogger.startLoggingToBuffer();
@@ -1754,6 +1497,8 @@ public void testBug27655() throws Exception {
@Test
public void testFailoverReadOnly() throws Exception {
Properties props = getHostFreePropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.queriesBeforeRetrySource.getKeyName(), "0");
props.setProperty(PropertyKey.secondsBeforeRetrySource.getKeyName(), "0"); // +^ enable fall back to primary as soon as possible
@@ -1825,19 +1570,18 @@ public void testPropertiesDescriptionsKeys() throws Exception {
String description = dpi[i].description;
String propertyName = dpi[i].name;
- if (description.indexOf("Missing error message for key '") != -1 || description.startsWith("!")) {
- fail("Missing message for configuration property " + propertyName);
- }
-
- if (description.length() < 10) {
- fail("Suspiciously short description for configuration property " + propertyName);
- }
+ assertFalse(description.indexOf("Missing error message for key '") != -1 || description.startsWith("!"),
+ "Missing message for configuration property " + propertyName);
+ assertFalse(description.length() < 10, "Suspiciously short description for configuration property " + propertyName);
}
}
@Test
public void testBug29852() throws Exception {
- Connection lbConn = getLoadBalancedConnection();
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ Connection lbConn = getLoadBalancedConnection(props);
assertTrue(!lbConn.getClass().getName().startsWith("com.mysql.cj.jdbc"));
lbConn.close();
}
@@ -1853,7 +1597,10 @@ public void testBug29852() throws Exception {
public void testBug22643() throws Exception {
checkPingQuery(this.conn);
- Connection replConnection = getSourceReplicaReplicationConnection();
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ Connection replConnection = getSourceReplicaReplicationConnection(props);
try {
checkPingQuery(replConnection);
@@ -1863,7 +1610,7 @@ public void testBug22643() throws Exception {
}
}
- Connection lbConn = getLoadBalancedConnection();
+ Connection lbConn = getLoadBalancedConnection(props);
try {
checkPingQuery(lbConn);
@@ -1906,6 +1653,8 @@ private void checkPingQuery(Connection c) throws SQLException {
@Test
public void testBug31053() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.connectTimeout.getKeyName(), "2000");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), "random");
@@ -1921,6 +1670,8 @@ public void testBug31053() throws Exception {
@Test
public void testBug32877() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.connectTimeout.getKeyName(), "2000");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), "bestResponseTime");
@@ -1945,7 +1696,12 @@ public void testBug32877() throws Exception {
*/
@Test
public void testBug33734() throws Exception {
- Connection testConn = getConnectionWithProps("cachePrepStmts=true,useServerPrepStmts=false");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.cachePrepStmts.getKeyName(), "true");
+ props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "false");
+ Connection testConn = getConnectionWithProps(props);
try {
testConn.prepareStatement("SELECT 1");
} finally {
@@ -1962,7 +1718,10 @@ public void testBug33734() throws Exception {
public void testBug34703() throws Exception {
Method isValid = java.sql.Connection.class.getMethod("isValid", new Class>[] { Integer.TYPE });
- Connection newConn = getConnectionWithProps((Properties) null);
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ Connection newConn = getConnectionWithProps(props);
isValid.invoke(newConn, new Object[] { new Integer(1) });
Thread.sleep(2000);
assertTrue(((Boolean) isValid.invoke(newConn, new Object[] { new Integer(0) })).booleanValue());
@@ -1990,6 +1749,8 @@ public void testBug34937() throws Exception {
String url = urlBuf.toString();
url = "jdbc:mysql:replication:" + url.substring(url.indexOf("jdbc:mysql:") + "jdbc:mysql:".length());
ds.setURL(url);
+ ds.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ ds.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
Connection replConn = ds.getPooledConnection().getConnection();
boolean readOnly = false;
@@ -2006,8 +1767,11 @@ public void testBug34937() throws Exception {
@Test
public void testBug35660() throws Exception {
- Connection lbConn = getLoadBalancedConnection(null);
- Connection lbConn2 = getLoadBalancedConnection(null);
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ Connection lbConn = getLoadBalancedConnection(props);
+ Connection lbConn2 = getLoadBalancedConnection(props);
try {
assertEquals(this.conn, this.conn);
@@ -2023,34 +1787,35 @@ public void testBug35660() throws Exception {
@Test
public void testBug37570() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.characterEncoding.getKeyName(), "utf-8");
props.setProperty(PropertyKey.passwordCharacterEncoding.getKeyName(), "utf-8");
- // TODO enable for usual connection?
- Connection adminConn = getAdminConnectionWithProps(props);
-
- if (adminConn != null) {
-
- String unicodePassword = "\u0430\u0431\u0432"; // Cyrillic string
- String user = "bug37570";
- Statement adminStmt = adminConn.createStatement();
+ Connection con = getConnectionWithProps(props);
+ String unicodePassword = "\u0430\u0431\u0432"; // Cyrillic string
+ String user = "bug37570";
+ Statement st = con.createStatement();
- adminStmt.executeUpdate("create user '" + user + "'@'127.0.0.1' identified by 'foo'");
- adminStmt.executeUpdate("grant usage on *.* to '" + user + "'@'127.0.0.1'");
- adminStmt.executeUpdate("update mysql.user set password=PASSWORD('" + unicodePassword + "') where user = '" + user + "'");
- adminStmt.executeUpdate("flush privileges");
+ createUser(st, "'" + user + "'@'%'", "identified WITH mysql_native_password");
+ st.executeUpdate("grant all on *.* to '" + user + "'@'%'");
+ st.executeUpdate(versionMeetsMinimum(5, 7, 6) ? "ALTER USER '" + user + "'@'%' IDENTIFIED BY '" + unicodePassword + "'"
+ : "SET PASSWORD FOR '" + user + "'@'%' = PASSWORD('" + unicodePassword + "')");
+ st.executeUpdate("flush privileges");
- try {
- ((JdbcConnection) adminConn).changeUser(user, unicodePassword);
- } catch (SQLException sqle) {
- assertTrue(false, "Connection with non-latin1 password failed");
- }
+ try {
+ ((JdbcConnection) con).changeUser(user, unicodePassword);
+ } catch (SQLException sqle) {
+ sqle.printStackTrace();
+ fail("Connection with non-latin1 password failed");
}
}
@Test
public void testUnreliableSocketFactory() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), "bestResponseTime");
Connection conn2 = this.getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
assertNotNull(this.conn, "Connection should not be null");
@@ -2073,6 +1838,8 @@ public void testReplicationConnectionGroupHostManagement() throws Exception {
String replicationGroup1 = "rg1";
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.replicationConnectionGroup.getKeyName(), replicationGroup1);
props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "3");
props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "1");
@@ -2139,6 +1906,8 @@ public void testReplicationConnectionGroupHostManagement() throws Exception {
@Test
public void testReplicationConnectionHostManagement() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "3");
props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "1");
@@ -2230,6 +1999,8 @@ public void testReplicationConnectionHostManagement() throws Exception {
@Test
public void testReplicationConnectWithNoSource() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "3");
props.setProperty(PropertyKey.allowSourceDownConnections.getKeyName(), "true");
@@ -2262,6 +2033,8 @@ public void testReplicationConnectWithNoSource() throws Exception {
@Test
public void testReplicationConnectWithMultipleSources() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "3");
Set configs = new HashSet<>();
@@ -2284,6 +2057,8 @@ public void testReplicationConnectWithMultipleSources() throws Exception {
@Test
public void testReplicationConnectionMemory() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "3");
String replicationGroup = "memoryGroup";
props.setProperty(PropertyKey.replicationConnectionGroup.getKeyName(), replicationGroup);
@@ -2328,6 +2103,8 @@ public void testReplicationConnectionMemory() throws Exception {
@Test
public void testReplicationJMXInterfaces() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "3");
String replicationGroup = "testReplicationJMXInterfaces";
props.setProperty(PropertyKey.replicationConnectionGroup.getKeyName(), replicationGroup);
@@ -2402,36 +2179,42 @@ private ReplicationGroupManagerMBean getReplicationMBean() throws Exception {
@Test
public void testBug43421() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), "bestResponseTime");
- Connection conn2 = this.getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
+ final Connection conn2 = this.getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
// both connections are live now
UnreliableSocketFactory.downHost("second");
UnreliableSocketFactory.downHost("first");
- try {
+
+ assertThrows("Pings should not succeed when one host is down and using loadbalance w/o global blocklist.", SQLException.class, () -> {
conn2.createStatement().execute("/* ping */");
- fail("Pings will not succeed when one host is down and using loadbalance w/o global blocklist.");
- } catch (SQLException sqlEx) {
- }
+ return null;
+ });
+
+ conn2.close();
UnreliableSocketFactory.flushAllStaticData();
props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.loadBalanceBlocklistTimeout.getKeyName(), "200");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), "bestResponseTime");
- conn2 = this.getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
+ Connection conn3 = this.getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
assertNotNull(this.conn, "Connection should not be null");
- conn2.createStatement().execute("SELECT 1");
- conn2.createStatement().execute("SELECT 1");
+ conn3.createStatement().execute("SELECT 1");
+ conn3.createStatement().execute("SELECT 1");
// both connections are live now
UnreliableSocketFactory.downHost("second");
try {
- conn2.createStatement().execute("/* ping */");
+ conn3.createStatement().execute("/* ping */");
} catch (SQLException sqlEx) {
fail("Pings should succeed even though host is down.");
}
@@ -2440,6 +2223,8 @@ public void testBug43421() throws Exception {
@Test
public void testBug48442() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), "random");
Connection conn2 = this.getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
@@ -2559,7 +2344,11 @@ public void testBug46637() throws Exception {
UnreliableSocketFactory.downHost(hostname);
try {
- Connection noConn = getConnectionWithProps("socketFactory=testsuite.UnreliableSocketFactory");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.socketFactory.getKeyName(), UnreliableSocketFactory.class.getName());
+ Connection noConn = getConnectionWithProps(props);
noConn.close();
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().indexOf("has not received") != -1);
@@ -2616,9 +2405,13 @@ public void testBug46925() throws Exception {
Xid txid = new MysqlXid(new byte[] { 0x1 }, new byte[] { 0xf }, 3306);
+ xads1.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ xads1.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
xads1.getProperty(PropertyKey.pinGlobalTxToPhysicalConnection).setValue(true);
xads1.setUrl(dbUrl);
+ xads2.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ xads2.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
xads2.getProperty(PropertyKey.pinGlobalTxToPhysicalConnection).setValue(true);
xads2.setUrl(dbUrl);
@@ -2638,26 +2431,29 @@ public void testBug46925() throws Exception {
@Test
public void testBug47494() throws Exception {
try {
- getConnectionWithProps("jdbc:mysql://localhost:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
+ getConnectionWithProps(
+ "jdbc:mysql://localhost:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory,sslMode=DISABLED,allowPublicKeyRetrieval=true");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
try {
- getConnectionWithProps("jdbc:mysql://:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
+ getConnectionWithProps(
+ "jdbc:mysql://:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory,sslMode=DISABLED,allowPublicKeyRetrieval=true");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
try {
- getConnectionWithProps("jdbc:mysql://:9999,:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
+ getConnectionWithProps(
+ "jdbc:mysql://:9999,:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory,sslMode=DISABLED,allowPublicKeyRetrieval=true");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
try {
getConnectionWithProps(
- "jdbc:mysql://localhost:9999,localhost:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
+ "jdbc:mysql://localhost:9999,localhost:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory,sslMode=DISABLED,allowPublicKeyRetrieval=true");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
@@ -2692,6 +2488,8 @@ public void testBug48486() throws Exception {
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setUrl(newUrl);
+ ds.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ ds.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
Connection c = ds.getPooledConnection().getConnection();
this.rs = c.createStatement().executeQuery("SELECT 1");
@@ -2701,6 +2499,8 @@ public void testBug48486() throws Exception {
@Test
public void testBug48605() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), "random");
props.setProperty(PropertyKey.selfDestructOnPingMaxOperations.getKeyName(), "5");
final Connection conn2 = this.getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
@@ -2739,7 +2539,11 @@ public Void call() throws Exception {
@Test
public void testBug49700() throws Exception {
- Connection c = getConnectionWithProps("sessionVariables=@foo='bar'");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.sessionVariables.getKeyName(), "@foo='bar'");
+ Connection c = getConnectionWithProps(props);
assertEquals("bar", getSingleIndexedValueWithQuery(c, 1, "SELECT @foo"));
((com.mysql.cj.jdbc.JdbcConnection) c).resetServerState();
assertEquals("bar", getSingleIndexedValueWithQuery(c, 1, "SELECT @foo"));
@@ -2748,6 +2552,8 @@ public void testBug49700() throws Exception {
@Test
public void testBug51266() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
Set downedHosts = new HashSet<>();
downedHosts.add("first");
@@ -2766,6 +2572,8 @@ public void testBug51266() throws Exception {
@Test
public void testBug51643() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), SequentialBalanceStrategy.class.getName());
Connection lbConn = getUnreliableLoadBalancedConnection(new String[] { "first", "second" }, props);
@@ -2811,6 +2619,8 @@ public void testBug51643() throws Exception {
@Test
public void testBug51783() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), ForcedLoadBalanceStrategy.class.getName());
props.setProperty(PropertyKey.loadBalanceBlocklistTimeout.getKeyName(), "5000");
props.setProperty(PropertyKey.loadBalancePingTimeout.getKeyName(), "100");
@@ -2833,6 +2643,8 @@ public void testBug51783() throws Exception {
conn2.close();
props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), ForcedLoadBalanceStrategy.class.getName());
props.setProperty(PropertyKey.loadBalanceBlocklistTimeout.getKeyName(), "5000");
props.setProperty(PropertyKey.loadBalancePingTimeout.getKeyName(), "100");
@@ -2887,6 +2699,8 @@ public com.mysql.cj.jdbc.ConnectionImpl pickConnection(InvocationHandler proxy,
@Test
public void testAutoCommitLB() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), CountingReBalanceStrategy.class.getName());
props.setProperty(PropertyKey.loadBalanceAutoCommitStatementThreshold.getKeyName(), "3");
@@ -2962,6 +2776,8 @@ public com.mysql.cj.jdbc.ConnectionImpl pickConnection(InvocationHandler proxy,
@Test
public void testBug56429() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.socketFactory.getKeyName(), "testsuite.UnreliableSocketFactory");
@@ -3014,10 +2830,9 @@ public void testBug56429() throws Exception {
assert (endConnCount > 0);
- if (endConnCount - startConnCount >= 20) {
- // this may be bogus if run on a real system, we should probably look to see they're coming from this testsuite?
- fail("We're leaking connections even when not failed over");
- }
+ assertFalse(endConnCount - startConnCount >= 20,
+ // this may be bogus if run on a real system, we should probably look to see they're coming from this testsuite?
+ "We're leaking connections even when not failed over");
} finally {
if (failoverConnection != null) {
failoverConnection.close();
@@ -3034,6 +2849,8 @@ public void testBug56955() throws Exception {
@Test
public void testBug58706() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.socketFactory.getKeyName(), "testsuite.UnreliableSocketFactory");
@@ -3092,7 +2909,12 @@ public void testBug58706() throws Exception {
@Test
public void testStatementComment() throws Exception {
- Connection c = getConnectionWithProps("autoGenerateTestcaseScript=true,logger=StandardLogger");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.autoGenerateTestcaseScript.getKeyName(), "true");
+ props.setProperty(PropertyKey.logger.getKeyName(), "StandardLogger");
+ Connection c = getConnectionWithProps(props);
PrintStream oldErr = System.err;
try {
@@ -3122,7 +2944,15 @@ public void testStatementComment() throws Exception {
@Test
public void testReconnectWithCachedConfig() throws Exception {
- Connection rConn = getConnectionWithProps("autoReconnect=true,initialTimeout=2,maxReconnects=3,cacheServerConfiguration=true,elideSetAutoCommits=true");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
+ props.setProperty(PropertyKey.initialTimeout.getKeyName(), "2");
+ props.setProperty(PropertyKey.maxReconnects.getKeyName(), "3");
+ props.setProperty(PropertyKey.cacheServerConfiguration.getKeyName(), "true");
+ props.setProperty(PropertyKey.elideSetAutoCommits.getKeyName(), "true");
+ Connection rConn = getConnectionWithProps(props);
String threadId = getSingleIndexedValueWithQuery(rConn, 1, "select connection_id()").toString();
killConnection(this.conn, threadId);
boolean detectedDeadConn = false;
@@ -3139,14 +2969,15 @@ public void testReconnectWithCachedConfig() throws Exception {
assertTrue(detectedDeadConn);
rConn.prepareStatement("SELECT 1").execute();
- Connection rConn2 = getConnectionWithProps(
- "autoReconnect=true,initialTimeout=2,maxReconnects=3,cacheServerConfiguration=true,elideSetAutoCommits=true");
+ Connection rConn2 = getConnectionWithProps(props);
rConn2.prepareStatement("SELECT 1").execute();
}
@Test
public void testBug61201() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.sessionVariables.getKeyName(), "FOREIGN_KEY_CHECKS=0");
props.setProperty(PropertyKey.characterEncoding.getKeyName(), "latin1");
props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
@@ -3159,6 +2990,8 @@ public void testBug61201() throws Exception {
@Test
public void testChangeUser() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
Connection testConn = getConnectionWithProps(props);
Statement testStmt = testConn.createStatement();
@@ -3186,38 +3019,40 @@ public void testChangeUser() throws Exception {
@Test
public void testChangeUserNoDb() throws Exception {
String databaseName = "testchangeusernodb";
-
this.stmt.executeUpdate("DROP DATABASE IF EXISTS " + databaseName);
- Properties props = getPropertiesFromTestsuiteUrl();
- props.setProperty(PropertyKey.createDatabaseIfNotExist.getKeyName(), "true");
- props.setProperty(PropertyKey.DBNAME.getKeyName(), databaseName);
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ try {
+ Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.createDatabaseIfNotExist.getKeyName(), "true");
+ props.setProperty(PropertyKey.DBNAME.getKeyName(), databaseName);
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- Connection con = getConnectionWithProps(props);
+ Connection con = getConnectionWithProps(props);
- this.rs = this.stmt.executeQuery("show databases like '" + databaseName + "'");
- if (this.rs.next()) {
+ this.rs = this.stmt.executeQuery("show databases like '" + databaseName + "'");
+ assertTrue(this.rs.next(), "Database " + databaseName + " is not found.");
assertEquals(databaseName, this.rs.getString(1));
- } else {
- fail("Database " + databaseName + " is not found.");
- }
- ((com.mysql.cj.jdbc.JdbcConnection) con).changeUser(props.getProperty(PropertyKey.USER.getKeyName()),
- props.getProperty(PropertyKey.PASSWORD.getKeyName()));
+ ((com.mysql.cj.jdbc.JdbcConnection) con).changeUser(props.getProperty(PropertyKey.USER.getKeyName()),
+ props.getProperty(PropertyKey.PASSWORD.getKeyName()));
- this.rs = con.createStatement().executeQuery("select DATABASE()");
- assertTrue(this.rs.next());
- assertEquals(databaseName, this.rs.getString(1));
+ this.rs = con.createStatement().executeQuery("select DATABASE()");
+ assertTrue(this.rs.next());
+ assertEquals(databaseName, this.rs.getString(1));
- con.close();
+ con.close();
+ } finally {
+ this.stmt.executeUpdate("DROP DATABASE IF EXISTS " + databaseName);
+ }
}
@Test
public void testChangeUserClosedConn() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
- Connection newConn = getConnectionWithProps((Properties) null);
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ Connection newConn = getConnectionWithProps(props);
try {
newConn.close();
@@ -3237,6 +3072,8 @@ public void testChangeUserClosedConn() throws Exception {
@Test
public void testBug63284() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.socketFactory.getKeyName(), "testsuite.UnreliableSocketFactory");
@@ -3292,10 +3129,11 @@ public void testBug63284() throws Exception {
@Test
public void testDefaultPlugin() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7), "MySQL 5.5.7+ is required to run this test.");
+
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), "");
assertThrows(SQLException.class, "Improper value \"\" for property 'defaultAuthenticationPlugin'\\.", () -> getConnectionWithProps(props));
@@ -3319,10 +3157,11 @@ public void testDefaultPlugin() throws Exception {
@Test
public void testDisabledPlugins() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7), "MySQL 5.5.7+ is required to run this test.");
+
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
// Disable the built-in default authentication plugin, by name.
props.setProperty(PropertyKey.disabledAuthenticationPlugins.getKeyName(), "mysql_native_password");
@@ -3369,9 +3208,8 @@ public void testDisabledPlugins() throws Exception {
@Test
public void testAuthTestPlugin() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7) || isSysPropDefined(PropertyDefinitions.SYSP_testsuite_no_server_testsuite)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7), "MySQL 5.5.7+ is required to run this test.");
+
boolean installPluginInRuntime = false;
try {
// Install plugin if required.
@@ -3384,8 +3222,17 @@ public void testAuthTestPlugin() throws Exception {
}
if (installPluginInRuntime) {
- String ext = isServerRunningOnWindows() ? ".dll" : ".so";
- this.stmt.executeUpdate("INSTALL PLUGIN test_plugin_server SONAME 'auth_test_plugin" + ext + "'");
+ try {
+ String ext = isServerRunningOnWindows() ? ".dll" : ".so";
+ this.stmt.executeUpdate("INSTALL PLUGIN test_plugin_server SONAME 'auth_test_plugin" + ext + "'");
+ } catch (SQLException e) {
+ if (e.getErrorCode() == MysqlErrorNumbers.ER_CANT_OPEN_LIBRARY) {
+ installPluginInRuntime = false; // to disable plugin deinstallation attempt in a finally block
+ assumeTrue(false, "This test requires the server installed with the test package.");
+ } else {
+ throw e;
+ }
+ }
}
String dbname = getPropertiesFromTestsuiteUrl().getProperty(PropertyKey.DBNAME.getKeyName());
@@ -3403,6 +3250,8 @@ public void testAuthTestPlugin() throws Exception {
this.stmt.executeUpdate("FLUSH PRIVILEGES");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.USER.getKeyName(), "wl5851user1");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "wl5851user1prx");
props.setProperty(PropertyKey.authenticationPlugins.getKeyName(), AuthTestPlugin.class.getName());
@@ -3423,24 +3272,30 @@ public void testAuthTestPlugin() throws Exception {
@Test
public void testTwoQuestionsPlugin() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7) || isSysPropDefined(PropertyDefinitions.SYSP_testsuite_no_server_testsuite)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7), "MySQL 5.5.7+ is required to run this test.");
+
boolean installPluginInRuntime = false;
try {
// Install plugin if required.
this.rs = this.stmt.executeQuery("SELECT PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME='two_questions'");
if (this.rs.next()) {
- if (!this.rs.getString(1).equals("ACTIVE")) {
- fail("The 'two_questions' plugin is preinstalled but not active.");
- }
+ assumeTrue(this.rs.getString(1).equals("ACTIVE"), "The 'two_questions' plugin is preinstalled but not active.");
} else {
installPluginInRuntime = true;
}
if (installPluginInRuntime) {
- String ext = isServerRunningOnWindows() ? ".dll" : ".so";
- this.stmt.executeUpdate("INSTALL PLUGIN two_questions SONAME 'auth" + ext + "'");
+ try {
+ String ext = isServerRunningOnWindows() ? ".dll" : ".so";
+ this.stmt.executeUpdate("INSTALL PLUGIN two_questions SONAME 'auth" + ext + "'");
+ } catch (SQLException e) {
+ if (e.getErrorCode() == MysqlErrorNumbers.ER_CANT_OPEN_LIBRARY) {
+ installPluginInRuntime = false; // to disable plugin deinstallation attempt in a finally block
+ assumeTrue(false, "This test requires the server installed with the test package.");
+ } else {
+ throw e;
+ }
+ }
}
String dbname = getPropertiesFromTestsuiteUrl().getProperty(PropertyKey.DBNAME.getKeyName());
@@ -3455,6 +3310,8 @@ public void testTwoQuestionsPlugin() throws Exception {
this.stmt.executeUpdate("FLUSH PRIVILEGES");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.USER.getKeyName(), "wl5851user2");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "two_questions_password");
props.setProperty(PropertyKey.authenticationPlugins.getKeyName(), TwoQuestionsPlugin.class.getName());
@@ -3474,24 +3331,30 @@ public void testTwoQuestionsPlugin() throws Exception {
@Test
public void testThreeAttemptsPlugin() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7) || isSysPropDefined(PropertyDefinitions.SYSP_testsuite_no_server_testsuite)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7), "MySQL 5.5.7+ is required to run this test.");
+
boolean installPluginInRuntime = false;
try {
// Install plugin if required.
this.rs = this.stmt.executeQuery("SELECT PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME='three_attempts'");
if (this.rs.next()) {
- if (!this.rs.getString(1).equals("ACTIVE")) {
- fail("The 'three_attempts' plugin is preinstalled but not active.");
- }
+ assumeTrue(this.rs.getString(1).equals("ACTIVE"), "The 'three_attempts' plugin is preinstalled but not active.");
} else {
installPluginInRuntime = true;
}
if (installPluginInRuntime) {
- String ext = isServerRunningOnWindows() ? ".dll" : ".so";
- this.stmt.executeUpdate("INSTALL PLUGIN three_attempts SONAME 'auth" + ext + "'");
+ try {
+ String ext = isServerRunningOnWindows() ? ".dll" : ".so";
+ this.stmt.executeUpdate("INSTALL PLUGIN three_attempts SONAME 'auth" + ext + "'");
+ } catch (SQLException e) {
+ if (e.getErrorCode() == MysqlErrorNumbers.ER_CANT_OPEN_LIBRARY) {
+ installPluginInRuntime = false; // to disable plugin deinstallation attempt in a finally block
+ assumeTrue(false, "This test requires the server installed with the test package.");
+ } else {
+ throw e;
+ }
+ }
}
String dbname = getPropertiesFromTestsuiteUrl().getProperty(PropertyKey.DBNAME.getKeyName());
@@ -3506,6 +3369,8 @@ public void testThreeAttemptsPlugin() throws Exception {
this.stmt.executeUpdate("FLUSH PRIVILEGES");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.USER.getKeyName(), "wl5851user3");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "three_attempts_password");
props.setProperty(PropertyKey.authenticationPlugins.getKeyName(), ThreeAttemptsPlugin.class.getName());
@@ -3640,11 +3505,8 @@ public void reset() {
@Test
public void testOldPasswordPlugin() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7) || versionMeetsMinimum(5, 7, 5)) {
- // As of 5.7.5, support for mysql_old_password is removed.
- System.out.println("testOldPasswordPlugin was skipped: This test is only run for 5.5.7 - 5.7.4 server versions.");
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7) && !versionMeetsMinimum(5, 7, 5),
+ "testOldPasswordPlugin was skipped: This test only run for 5.5.7 - 5.7.4 server versions.");
Connection testConn = null;
try {
@@ -3665,6 +3527,8 @@ public void testOldPasswordPlugin() throws Exception {
this.stmt.executeUpdate("flush privileges");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
// connect with default plugin
props.setProperty(PropertyKey.USER.getKeyName(), "bug64983user1");
@@ -3749,9 +3613,13 @@ public void testOldPasswordPlugin() throws Exception {
@Test
public void testAuthCleartextPlugin() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7) || isSysPropDefined(PropertyDefinitions.SYSP_testsuite_no_server_testsuite)) {
- return;
- }
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
boolean installPluginInRuntime = false;
try {
// Install plugin if required.
@@ -3764,8 +3632,17 @@ public void testAuthCleartextPlugin() throws Exception {
}
if (installPluginInRuntime) {
- String ext = isServerRunningOnWindows() ? ".dll" : ".so";
- this.stmt.executeUpdate("INSTALL PLUGIN cleartext_plugin_server SONAME 'auth_test_plugin" + ext + "'");
+ try {
+ String ext = isServerRunningOnWindows() ? ".dll" : ".so";
+ this.stmt.executeUpdate("INSTALL PLUGIN cleartext_plugin_server SONAME 'auth_test_plugin" + ext + "'");
+ } catch (SQLException e) {
+ if (e.getErrorCode() == MysqlErrorNumbers.ER_CANT_OPEN_LIBRARY) {
+ installPluginInRuntime = false; // To disable plugin deinstallation attempt in the finally block.
+ assumeTrue(false, "This test requires a server installed with the test package.");
+ } else {
+ throw e;
+ }
+ }
}
String dbname = getPropertiesFromTestsuiteUrl().getProperty(PropertyKey.DBNAME.getKeyName());
@@ -3782,7 +3659,7 @@ public void testAuthCleartextPlugin() throws Exception {
Properties props = new Properties();
props.setProperty(PropertyKey.USER.getKeyName(), "wl5735user");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- props.setProperty(PropertyKey.sslMode.getKeyName(), "DISABLED");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
assertThrows(SQLException.class, "SSL connection required for plugin \"mysql_clear_password\"\\. Check if 'sslMode' is enabled\\.",
() -> getConnectionWithProps(props));
@@ -3790,7 +3667,7 @@ public void testAuthCleartextPlugin() throws Exception {
String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "password");
- props.setProperty(PropertyKey.sslMode.getKeyName(), "REQUIRED");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
try (Connection testConn = getConnectionWithProps(props)) {
assertTrue(((MysqlConnection) testConn).getSession().isSSLEstablished(), "SSL connection isn't actually established!");
@@ -3809,345 +3686,235 @@ public void testAuthCleartextPlugin() throws Exception {
}
/**
- * This test requires two server instances:
- * 1) main test server pointed by com.mysql.cj.testsuite.url variable configured without RSA encryption support (sha256_password_private_key_path,
- * sha256_password_public_key_path, caching_sha2_password_private_key_path and caching_sha2_password_public_key_path config options are unset).
- * 2) additional server instance pointed by com.mysql.cj.testsuite.url.openssl variable configured with default-authentication-plugin=sha256_password and
- * RSA encryption enabled.
- *
- * To run this test please add this variable to ant call:
- * -Dcom.mysql.cj.testsuite.url.openssl=jdbc:mysql://localhost:3307/test?user=root&password=pwd
+ * Test for sha256_password authentication.
*
* @throws Exception
*/
@Test
public void testSha256PasswordPlugin() throws Exception {
+ assumeTrue(versionMeetsMinimum(5, 6, 5), "MySQL 5.6.5+ is required to run this test.");
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(pluginIsActive(this.stmt, "sha256_password"), "sha256_password plugin required to run this test");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "password");
- /*
- * Test against server without RSA support.
- */
- if (versionMeetsMinimum(5, 6, 5)) {
- if (!pluginIsActive(this.stmt, "sha256_password")) {
- fail("sha256_password required to run this test");
- }
-
+ try {
// newer GPL servers, like 8.0.4+, are using OpenSSL and can use RSA encryption, while old ones compiled with yaSSL cannot
- boolean gplWithRSA = allowsRsa(this.stmt);
+ boolean withRSA = allowsRsa(this.stmt);
+ boolean withTestRsaKeys = supportsTestSha256PasswordKeys(this.stmt);
+
+ // create user with long password and sha256_password auth
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
+ }
+ createUser(this.stmt, "'wl5602user'@'%'", "IDENTIFIED WITH sha256_password");
+ this.stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602user'@'%'");
+ createUser(this.stmt, "'wl5602nopassword'@'%'", "identified WITH sha256_password");
+ this.stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602nopassword'@'%'");
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords= 2");
+ this.stmt.executeUpdate("SET SESSION old_passwords= 2");
+ }
+ this.stmt.executeUpdate(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl5602user'@'%' IDENTIFIED BY 'pwd'"
+ : "SET PASSWORD FOR 'wl5602user'@'%' = PASSWORD('pwd')");
+ this.stmt.executeUpdate("FLUSH PRIVILEGES");
- try {
- if (!versionMeetsMinimum(8, 0, 5)) {
- this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
- }
- createUser("'wl5602user'@'%'", "IDENTIFIED WITH sha256_password");
- this.stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602user'@'%'");
- createUser("'wl5602nopassword'@'%'", "IDENTIFIED WITH sha256_password");
- this.stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602nopassword'@'%'");
- if (!versionMeetsMinimum(8, 0, 5)) {
- this.stmt.executeUpdate("SET GLOBAL old_passwords= 2");
- this.stmt.executeUpdate("SET SESSION old_passwords= 2");
- }
- this.stmt.executeUpdate(versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl5602user'@'%' IDENTIFIED BY 'pwd'"
- : "SET PASSWORD FOR 'wl5602user'@'%' = PASSWORD('pwd')");
- this.stmt.executeUpdate("FLUSH PRIVILEGES");
-
- final Properties propsNoRetrieval = new Properties();
- propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
- propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- final Properties propsNoRetrievalNoPassword = new Properties();
- propsNoRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- final Properties propsAllowRetrieval = new Properties();
- propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
- propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- final Properties propsAllowRetrievalNoPassword = new Properties();
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- // 1. without SSL
- // SQLException expected due to server doesn't recognize Public Key Retrieval packet
- assertThrows(SQLException.class, "Public Key Retrieval is not allowed", () -> getConnectionWithProps(propsNoRetrieval));
-
- if (gplWithRSA) {
- assertCurrentUser(null, propsAllowRetrieval, "wl5602user", false);
- } else {
- assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(propsAllowRetrieval));
- }
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 2. with serverRSAPublicKeyFile specified
- // SQLException expected due to server doesn't recognize RSA encrypted payload
- propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
-
- assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(propsNoRetrieval));
- assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(propsAllowRetrieval));
-
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 3. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- assertCurrentUser(null, propsNoRetrieval, "wl5602user", true);
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(null, propsAllowRetrieval, "wl5602user", true);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // over SSL with client-default Sha256PasswordPlugin
- propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- propsNoRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
-
- assertCurrentUser(null, propsNoRetrieval, "wl5602user", true);
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(null, propsAllowRetrieval, "wl5602user", true);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
+ final Properties propsNoRetrieval = new Properties();
+ propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
+ propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- } finally {
- this.stmt.executeUpdate("FLUSH PRIVILEGES");
- if (!versionMeetsMinimum(8, 0, 5)) {
- this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
- }
- }
- }
+ final Properties propsNoRetrievalNoPassword = new Properties();
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- /*
- * Test against server with RSA support.
- */
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 6, 5)) {
+ final Properties propsAllowRetrieval = new Properties();
+ propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
+ propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
+ propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- if (!pluginIsActive(this.sha256Stmt, "sha256_password")) {
- fail("sha256_password required to run this test");
- }
- if (!allowsRsa(this.sha256Stmt)) {
- fail("RSA encryption must be enabled on " + sha256Url + " to run this test");
+ final Properties propsAllowRetrievalNoPassword = new Properties();
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
+ // 1. with client-default MysqlNativePasswordPlugin
+ propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
+ propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
+
+ // 1.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+
+ assertThrows(SQLException.class, "Public Key Retrieval is not allowed", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
+
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
+ if (withRSA) {
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
+ } else {
+ assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
+ }
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
+
+ // 1.2. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", true);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", true);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
+
+ // 2. with client-default Sha256PasswordPlugin
+ propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
+ propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
+
+ // 2.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+
+ assertThrows(SQLException.class, "Public Key Retrieval is not allowed", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
+
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
+ if (withRSA) {
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
+ } else {
+ assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
+ }
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
+
+ // 2.2. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", true);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
+
+ // 3. with serverRSAPublicKeyFile specified
+ propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+
+ // 3.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+
+ if (withRSA && withTestRsaKeys) {
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", false);
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
+ } else {
+ assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
+ assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
}
- try {
- // create user with long password and sha256_password auth
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
- }
- createUser(this.sha256Stmt, "'wl5602user'@'%'", "IDENTIFIED WITH sha256_password");
- this.sha256Stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602user'@'%'");
- createUser(this.sha256Stmt, "'wl5602nopassword'@'%'", "identified WITH sha256_password");
- this.sha256Stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602nopassword'@'%'");
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords= 2");
- this.sha256Stmt.executeUpdate("SET SESSION old_passwords= 2");
- }
- this.sha256Stmt.executeUpdate(
- ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl5602user'@'%' IDENTIFIED BY 'pwd'"
- : "SET PASSWORD FOR 'wl5602user'@'%' = PASSWORD('pwd')");
- this.sha256Stmt.executeUpdate("FLUSH PRIVILEGES");
-
- final Properties propsNoRetrieval = new Properties();
- propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
- propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
-
- final Properties propsNoRetrievalNoPassword = new Properties();
- propsNoRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
-
- final Properties propsAllowRetrieval = new Properties();
- propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
- propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
-
- final Properties propsAllowRetrievalNoPassword = new Properties();
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
-
- // 1. with client-default MysqlNativePasswordPlugin
- propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
- propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
-
- // 1.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- assertThrows(SQLException.class, "Public Key Retrieval is not allowed", () -> getConnectionWithProps(sha256Url, propsNoRetrieval));
-
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl5602user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 1.2. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl5602user", true);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl5602user", true);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 2. with client-default Sha256PasswordPlugin
- propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- propsNoRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
-
- // 2.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- assertThrows(SQLException.class, "Public Key Retrieval is not allowed", () -> getConnectionWithProps(sha256Url, propsNoRetrieval));
-
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl5602user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 2.2. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl5602user", true);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl5602user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 3. with serverRSAPublicKeyFile specified
- propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
-
- // 3.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl5602user", false);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl5602user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 3.2. Runtime setServerRSAPublicKeyFile must be denied
- final Connection c2 = getConnectionWithProps(sha256Url, propsNoRetrieval);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
+
+ // 3.2. Runtime setServerRSAPublicKeyFile must be denied
+ if (withRSA && withTestRsaKeys) {
+ final Connection c2 = getConnectionWithProps(dbUrl, propsNoRetrieval);
assertThrows(PropertyNotModifiableException.class, "Dynamic change of ''serverRSAPublicKeyFile'' is not allowed.", () -> {
((JdbcConnection) c2).getPropertySet().getProperty(PropertyKey.serverRSAPublicKeyFile).setValue("src/test/config/ssl-test-certs/mykey.pub");
return null;
});
c2.close();
+ }
- // 3.3. Runtime setAllowPublicKeyRetrieval must be denied
- final Connection c3 = getConnectionWithProps(sha256Url, propsNoRetrieval);
- assertThrows(PropertyNotModifiableException.class, "Dynamic change of ''allowPublicKeyRetrieval'' is not allowed.", () -> {
- ((JdbcConnection) c3).getPropertySet().getProperty(PropertyKey.allowPublicKeyRetrieval).setValue(true);
+ // 3.4. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", true);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", true);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
+
+ // 4. with wrong serverRSAPublicKeyFile specified
+ propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
+ propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
+
+ // 4.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
+ () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
+ () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
+
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
+ assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
+ assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
+ assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
+
+ // 4.2. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
+ () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
+ () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
+
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
return null;
- });
- c3.close();
-
- // 3.4. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl5602user", true);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl5602nopassword", false);
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl5602user", true);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
-
- // 4. with wrong serverRSAPublicKeyFile specified
- propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
- propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
-
- // 4.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsNoRetrieval));
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword));
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsAllowRetrieval));
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword));
-
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(sha256Url, propsNoRetrieval));
- assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword));
- assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(sha256Url, propsAllowRetrieval));
- assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword));
-
- // 4.2. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsNoRetrieval));
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword));
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsAllowRetrieval));
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*",
- () -> getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword));
-
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword));
- assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(sha256Url, propsAllowRetrieval));
- assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword));
-
- } finally {
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
}
+ });
+ assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
+ assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
+ assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
+
+ } finally {
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
}
}
}
@@ -4206,192 +3973,6 @@ public void testBug36662() throws Exception {
}
}
- @Test
- public void testBug37931() throws Exception {
- Connection _conn = null;
- Properties props = new Properties();
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "ISO88591");
-
- try {
- _conn = getConnectionWithProps(props);
- assertTrue(false, "This point should not be reached.");
- } catch (Exception e) {
- assertEquals("Can't map ISO88591 given for characterSetResults to a supported MySQL encoding.", e.getMessage());
- } finally {
- if (_conn != null) {
- _conn.close();
- }
- }
-
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "null");
-
- try {
- _conn = getConnectionWithProps(props);
-
- Statement _stmt = _conn.createStatement();
- ResultSet _rs = _stmt.executeQuery("show variables where variable_name='character_set_results'");
- if (_rs.next()) {
- String res = _rs.getString(2);
- if (res == null || "NULL".equalsIgnoreCase(res) || res.length() == 0) {
- assertTrue(true);
- } else {
- assertTrue(false);
- }
- }
- } finally {
- if (_conn != null) {
- _conn.close();
- }
- }
- }
-
- @Test
- public void testBug64205() throws Exception {
- Properties props = getPropertiesFromTestsuiteUrl();
- String dbname = props.getProperty(PropertyKey.DBNAME.getKeyName());
- if (dbname == null) {
- assertTrue(false, "No database selected");
- }
-
- props = new Properties();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "EUC_JP");
-
- Connection testConn = null;
- Statement testSt = null;
- ResultSet testRs = null;
- try {
- testConn = getConnectionWithProps(props);
- testSt = testConn.createStatement();
- testRs = testSt.executeQuery("SELECT * FROM `" + dbname + "`.`\u307b\u3052\u307b\u3052`");
- } catch (SQLException e1) {
- if (e1.getClass().getName().endsWith("SQLSyntaxErrorException")) {
- assertEquals("Table '" + dbname + ".\u307B\u3052\u307b\u3052' doesn't exist", e1.getMessage());
- } else if (e1.getErrorCode() == MysqlErrorNumbers.ER_FILE_NOT_FOUND) {
- // this could happen on Windows with 5.5 and 5.6 servers where BUG#14642248 exists
- assertTrue(e1.getMessage().contains("Can't find file"));
- } else {
- throw e1;
- }
-
- testSt.close();
- testConn.close();
-
- try {
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "SJIS");
- testConn = getConnectionWithProps(props);
- testSt = testConn.createStatement();
- testSt.execute("SET lc_messages = 'ru_RU'");
- testRs = testSt.executeQuery("SELECT * FROM `" + dbname + "`.`\u307b\u3052\u307b\u3052`");
- } catch (SQLException e2) {
- if (e2.getClass().getName().endsWith("SQLSyntaxErrorException")) {
- assertEquals("\u0422\u0430\u0431\u043b\u0438\u0446\u0430 '" + dbname
- + ".\u307b\u3052\u307b\u3052' \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442", e2.getMessage());
- } else if (e2.getErrorCode() == MysqlErrorNumbers.ER_FILE_NOT_FOUND) {
- // this could happen on Windows with 5.5 and 5.6 servers where BUG#14642248 exists
- assertTrue(e2.getMessage().indexOf("\u0444\u0430\u0439\u043b") > -1,
- "File not found error message should be russian but is this one: " + e2.getMessage());
- } else {
- throw e2;
- }
- }
-
- } finally {
- if (testRs != null) {
- testRs.close();
- }
- if (testSt != null) {
- testSt.close();
- }
- if (testConn != null) {
- testConn.close();
- }
- }
-
- // also test with explicit characterSetResults and cacheServerConfiguration
- try {
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "EUC_JP");
- props.setProperty(PropertyKey.cacheServerConfiguration.getKeyName(), "true");
- testConn = getConnectionWithProps(props);
- testSt = testConn.createStatement();
- testRs = testSt.executeQuery("SELECT * FROM `" + dbname + "`.`\u307b\u3052\u307b\u3052`");
- fail("Exception should be thrown for attemping to query non-existing table");
- } catch (SQLException e1) {
- if (e1.getClass().getName().endsWith("SQLSyntaxErrorException")) {
- assertEquals("Table '" + dbname + ".\u307B\u3052\u307b\u3052' doesn't exist", e1.getMessage());
- } else if (e1.getErrorCode() == MysqlErrorNumbers.ER_FILE_NOT_FOUND) {
- // this could happen on Windows with 5.5 and 5.6 servers where BUG#14642248 exists
- assertTrue(e1.getMessage().contains("Can't find file"));
- } else {
- throw e1;
- }
- } finally {
- testConn.close();
- }
- props.remove(PropertyKey.cacheServerConfiguration.getKeyName());
-
- // Error messages may also be received after the handshake but before connection initialization is complete. This tests the interpretation of
- // errors thrown during this time window using a SatementInterceptor that throws an Exception while setting the session variables.
- // Start by getting the Latin1 version of the error to compare later.
- String latin1ErrorMsg = "";
- int latin1ErrorLen = 0;
- try {
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "Latin1");
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "Latin1");
- props.setProperty(PropertyKey.sessionVariables.getKeyName(), "lc_messages=ru_RU");
- props.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestBug64205QueryInterceptor.class.getName());
- testConn = getConnectionWithProps(props);
- fail("Exception should be trown for syntax error, caused by the exception interceptor");
- } catch (Exception e) {
- latin1ErrorMsg = e.getMessage();
- latin1ErrorLen = latin1ErrorMsg.length();
- }
- // Now compare with results when using a proper encoding.
- try {
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), "EUC_JP");
- props.setProperty(PropertyKey.characterSetResults.getKeyName(), "EUC_JP");
- props.setProperty(PropertyKey.sessionVariables.getKeyName(), "lc_messages=ru_RU");
- props.setProperty(PropertyKey.queryInterceptors.getKeyName(), TestBug64205QueryInterceptor.class.getName());
- testConn = getConnectionWithProps(props);
- fail("Exception should be trown for syntax error, caused by the exception interceptor");
- } catch (SQLException e) {
- // There should be the Russian version of this error message, correctly encoded. A mis-interpretation, e.g. decoding as latin1, would return a
- // wrong message with the wrong size.
- assertEquals(29 + dbname.length(), e.getMessage().length());
- assertFalse(latin1ErrorMsg.equals(e.getMessage()));
- assertFalse(latin1ErrorLen == e.getMessage().length());
- } finally {
- testConn.close();
- }
- }
-
- public static class TestBug64205QueryInterceptor extends BaseQueryInterceptor {
- private JdbcConnection connection;
-
- @Override
- public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
- this.connection = (JdbcConnection) conn;
- return super.init(conn, props, log);
- }
-
- @Override
- public M postProcess(M queryPacket, M originalResponsePacket) {
- String sql = StringUtils.toString(queryPacket.getByteBuffer(), 1, (queryPacket.getPosition() - 1));
- if (sql.contains("lc_messages=ru_RU")) {
- try {
- this.connection.createStatement()
- .executeQuery("SELECT * FROM `"
- + (this.connection.getPropertySet().getEnumProperty(PropertyKey.databaseTerm)
- .getValue() == DatabaseTerm.SCHEMA ? this.connection.getSchema() : this.connection.getCatalog())
- + "`.`\u307b\u3052\u307b\u3052`");
- } catch (Exception e) {
- throw ExceptionFactory.createException(e.getMessage(), e);
- }
- }
- return originalResponsePacket;
- }
- }
-
@Test
public void testIsLocal() throws Exception {
boolean normalState = ((ConnectionImpl) this.conn).isServerLocal();
@@ -4399,7 +3980,7 @@ public void testIsLocal() throws Exception {
if (normalState) {
Properties props = new Properties();
props.setProperty(PropertyKey.socketFactory.getKeyName(), NonLocalSocketFactory.class.getName());
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
boolean isLocal = ((ConnectionImpl) getConnectionWithProps(props)).isServerLocal();
@@ -4418,6 +3999,8 @@ public void testBug57662() throws Exception {
Connection conn_is = null;
try {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
props.setProperty(PropertyKey.useNanosForElapsedTime.getKeyName(), "true");
props.setProperty(PropertyKey.logger.getKeyName(), TestBug57662Logger.class.getName());
@@ -4452,6 +4035,8 @@ protected String logInternal(int level, Object msg, Throwable exception) {
@Test
public void testBug14563127() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), ForcedLoadBalanceStrategy.class.getName());
props.setProperty(PropertyKey.loadBalanceBlocklistTimeout.getKeyName(), "5000");
props.setProperty(PropertyKey.loadBalancePingTimeout.getKeyName(), "100");
@@ -4498,11 +4083,12 @@ public void testBug14563127() throws Exception {
*/
@Test
public void testBug11237() throws Exception {
+ assumeTrue(supportsLoadLocalInfile(this.stmt), "This test requires the server started with --local-infile=ON");
+
this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'max_allowed_packet'");
this.rs.next();
- if (this.rs.getInt(2) < 4 + 1024 * 1024 * 16 - 1) {
- fail("You need to increase max_allowed_packet to at least " + (4 + 1024 * 1024 * 16 - 1) + " before running this test!");
- }
+ long defaultMaxAllowedPacket = this.rs.getInt(2);
+ boolean changeMaxAllowedPacket = defaultMaxAllowedPacket < 4 + 1024 * 1024 * 16 - 1;
int requiredSize = 1024 * 1024 * 300;
int fieldLength = 1023;
@@ -4556,18 +4142,34 @@ public void testBug11237() throws Exception {
fileNameBuf = new StringBuilder(testFile.getAbsolutePath());
}
- Properties props = new Properties();
- props.setProperty(PropertyKey.allowLoadLocalInfile.getKeyName(), "true");
- props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
- Connection conn1 = getConnectionWithProps(props);
- Statement stmt1 = conn1.createStatement();
+ Connection conn1 = null;
+ try {
+ if (changeMaxAllowedPacket) {
+ this.stmt.executeUpdate("SET GLOBAL max_allowed_packet=" + 1024 * 1024 * 17);
+ }
+
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.allowLoadLocalInfile.getKeyName(), "true");
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
+ conn1 = getConnectionWithProps(props);
+ Statement stmt1 = conn1.createStatement();
- int updateCount = stmt1.executeUpdate("LOAD DATA LOCAL INFILE '" + fileNameBuf.toString() + "' INTO TABLE testBug11237 CHARACTER SET "
- + CharsetMapping.getMysqlCharsetForJavaEncoding(
- ((MysqlConnection) this.conn).getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue(),
- ((JdbcConnection) conn1).getServerVersion()));
+ int updateCount = stmt1.executeUpdate("LOAD DATA LOCAL INFILE '" + fileNameBuf.toString() + "' INTO TABLE testBug11237 CHARACTER SET "
+ + CharsetMappingWrapper.getStaticMysqlCharsetForJavaEncoding(
+ ((MysqlConnection) this.conn).getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue(),
+ ((JdbcConnection) conn1).getServerVersion()));
- assertTrue(updateCount == loops);
+ assertTrue(updateCount == loops);
+ } finally {
+ if (changeMaxAllowedPacket) {
+ this.stmt.executeUpdate("SET GLOBAL max_allowed_packet=" + defaultMaxAllowedPacket);
+ }
+ if (conn1 != null) {
+ conn1.close();
+ }
+ }
}
@Test
@@ -4583,9 +4185,8 @@ public void testStackOverflowOnMissingInterceptor() throws Exception {
@Test
public void testExpiredPassword() throws Exception {
- if (!versionMeetsMinimum(5, 6, 10)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 6, 10), "MySQL 5.6.10+ is required to run this test.");
+
Connection testConn = null;
Statement testSt = null;
ResultSet testRs = null;
@@ -4600,7 +4201,7 @@ public void testExpiredPassword() throws Exception {
createUser("'must_change2'@'%'", "IDENTIFIED BY 'aha'");
this.stmt.executeUpdate("grant all on `" + dbname + "`.* to 'must_change2'@'%'");
- // TODO workaround for Bug#77732, should be fixed in 5.7.9
+ // workaround for Bug#77732
if (versionMeetsMinimum(5, 7, 6) && !versionMeetsMinimum(8, 0, 5)) {
this.stmt.executeUpdate("GRANT SELECT ON `performance_schema`.`session_variables` TO 'must_change1'@'%'");
this.stmt.executeUpdate("GRANT SELECT ON `performance_schema`.`session_variables` TO 'must_change2'@'%'");
@@ -4610,6 +4211,8 @@ public void testExpiredPassword() throws Exception {
: "ALTER USER 'must_change1'@'%' PASSWORD EXPIRE, 'must_change2'@'%' PASSWORD EXPIRE");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
// ALTER USER can be prepared as of 5.6.8 (BUG#14646014)
if (versionMeetsMinimum(5, 6, 8)) {
@@ -4737,28 +4340,31 @@ public void testExpiredPassword() throws Exception {
}
/**
- * Tests connection attributes
+ * Tests fix for Bug#79612 (22362474), CONNECTION ATTRIBUTES LOST WHEN CONNECTING WITHOUT DEFAULT DATABASE.
*
* @throws Exception
*/
@Test
- public void testConnectionAttributes() throws Exception {
- if (versionMeetsMinimum(5, 6)) {
- testConnectionAttributes(dbUrl);
- }
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 6, 5)) {
- testConnectionAttributes(sha256Url);
- }
+ public void testBug79612() throws Exception {
+ assumeTrue(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 6, 5), "Requires MySQL 5.6.5+.");
+ testConnectionAttributes(getNoDbUrl(dbUrl), null);
+
+ createDatabase("testBug79612");
+ testConnectionAttributes(dbUrl, "testBug79612");
}
@Test
- private void testConnectionAttributes(String url) throws Exception {
- if (!versionMeetsMinimum(5, 6)) {
- return;
- }
+ private void testConnectionAttributes(String url, String db) throws Exception {
+ assumeTrue(versionMeetsMinimum(5, 6), "MySQL 5.6+ is required to run this test.");
+
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.connectionAttributes.getKeyName(), "first:one,again:two");
props.setProperty(PropertyKey.USER.getKeyName(), getPropertiesFromTestsuiteUrl().getProperty(PropertyKey.USER.getKeyName()));
+ if (db != null) {
+ props.setProperty(PropertyKey.DBNAME.getKeyName(), db);
+ }
Connection attConn = super.getConnectionWithProps(url, props);
ResultSet rslt = attConn.createStatement()
.executeQuery("SELECT * FROM performance_schema.session_connect_attrs WHERE processlist_id = CONNECTION_ID()");
@@ -4778,9 +4384,7 @@ private void testConnectionAttributes(String url) throws Exception {
while (rslt.next()) {
String key = rslt.getString(2);
String val = rslt.getString(3);
- if (!matchedCounts.containsKey(key)) {
- fail("Unexpected connection attribute key: " + key);
- }
+ assertTrue(matchedCounts.containsKey(key), "Unexpected connection attribute key: " + key);
matchedCounts.put(key, matchedCounts.get(key) + 1);
if (key.equals("_runtime_version")) {
assertEquals(Constants.JVM_VERSION, val);
@@ -4807,17 +4411,13 @@ private void testConnectionAttributes(String url) throws Exception {
attConn.close();
for (String key : matchedCounts.keySet()) {
- if (matchedCounts.get(key) != 1) {
- fail("Incorrect number of entries for key \"" + key + "\": " + matchedCounts.get(key));
- }
+ assertTrue(matchedCounts.get(key) == 1, "Incorrect number of entries for key \"" + key + "\": " + matchedCounts.get(key));
}
props.setProperty(PropertyKey.connectionAttributes.getKeyName(), "none");
attConn = super.getConnectionWithProps(url, props);
rslt = attConn.createStatement().executeQuery("SELECT * FROM performance_schema.session_connect_attrs WHERE processlist_id = CONNECTION_ID()");
- if (rslt.next()) {
- fail("Expected no connection attributes.");
- }
+ assertFalse(rslt.next(), "Expected no connection attributes.");
}
/**
@@ -4845,12 +4445,15 @@ public void testBug16224249() throws Exception {
String loadbalanceUrl = String.format("jdbc:mysql:loadbalance://%s,%s/%s?%s", hostSpec, hostSpec, database, configs.toString());
String failoverUrl = String.format("jdbc:mysql://%s,%s/%s?%s", hostSpec, "127.0.0.1:" + port, database, configs.toString());
+ Properties props2 = new Properties();
+ props2.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props2.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- Connection[] loadbalancedconnection = new Connection[] { new NonRegisteringDriver().connect(loadbalanceUrl, null),
- new NonRegisteringDriver().connect(loadbalanceUrl, null), new NonRegisteringDriver().connect(loadbalanceUrl, null) };
+ Connection[] loadbalancedconnection = new Connection[] { new NonRegisteringDriver().connect(loadbalanceUrl, props2),
+ new NonRegisteringDriver().connect(loadbalanceUrl, props2), new NonRegisteringDriver().connect(loadbalanceUrl, props2) };
- Connection[] failoverconnection = new Connection[] { new NonRegisteringDriver().connect(failoverUrl, null),
- new NonRegisteringDriver().connect(failoverUrl, null), new NonRegisteringDriver().connect(failoverUrl, null) };
+ Connection[] failoverconnection = new Connection[] { new NonRegisteringDriver().connect(failoverUrl, props2),
+ new NonRegisteringDriver().connect(failoverUrl, props2), new NonRegisteringDriver().connect(failoverUrl, props2) };
// WebLogic-style test
Class> mysqlCls = null;
@@ -4945,7 +4548,10 @@ public void testBug16224249() throws Exception {
public void testBug68763() throws Exception {
ReplicationConnection replConn = null;
- replConn = (ReplicationConnection) getSourceReplicaReplicationConnection();
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ replConn = (ReplicationConnection) getSourceReplicaReplicationConnection(props);
replConn.setReadOnly(true);
assertFalse(replConn.isSourceConnection(), "isSourceConnection() should be false for replica connection");
replConn.setReadOnly(false);
@@ -4960,6 +4566,8 @@ public void testBug68763() throws Exception {
@Test
public void testBug68733() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), ForcedLoadBalanceStrategy.class.getName());
props.setProperty(PropertyKey.loadBalancePingTimeout.getKeyName(), "100");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
@@ -5029,83 +4637,79 @@ public void testBug68733() throws Exception {
// leaving connection tied to replica2, bring replica2 down and replica1 up:
UnreliableSocketFactory.downHost("replica2");
- try {
+ assertThrows("Expected failure because current replica connection is down.", SQLException.class, () -> {
conn2.createStatement().execute("/* ping */ SELECT 1");
- fail("Expected failure because current replica connection is down.");
- } catch (SQLException e) {
- }
+ return null;
+ });
conn2.close();
ForcedLoadBalanceStrategy.forceFutureServer("replica1:" + portNumber, -1);
UnreliableSocketFactory.flushAllStaticData();
- conn2 = this.getUnreliableReplicationConnection(new String[] { "source", "replica1", "replica2" }, props);
- conn2.setAutoCommit(false);
+ ReplicationConnection conn3 = this.getUnreliableReplicationConnection(new String[] { "source", "replica1", "replica2" }, props);
+ conn3.setAutoCommit(false);
// go to replicas:
- conn2.setReadOnly(true);
+ conn3.setReadOnly(true);
// on replica1 now:
- conn2.commit();
+ conn3.commit();
ForcedLoadBalanceStrategy.forceFutureServer("replica2:" + portNumber, -1);
// on replica2 now:
- conn2.commit();
+ conn3.commit();
// disable source:
UnreliableSocketFactory.downHost("source");
// ping should succeed, because we're still attached to replicas:
- conn2.createStatement().execute("/* ping */ SELECT 1");
+ conn3.createStatement().execute("/* ping */ SELECT 1");
// bring source back up:
UnreliableSocketFactory.dontDownHost("source");
// get back to source, confirm it's recovered:
- conn2.commit();
- conn2.createStatement().execute("/* ping */ SELECT 1");
+ conn3.commit();
+ conn3.createStatement().execute("/* ping */ SELECT 1");
try {
- conn2.setReadOnly(false);
+ conn3.setReadOnly(false);
} catch (SQLException e) {
}
- conn2.commit();
+ conn3.commit();
// take down both replicas:
UnreliableSocketFactory.downHost("replica1");
UnreliableSocketFactory.downHost("replica2");
- assertTrue(conn2.isSourceConnection());
+ assertTrue(conn3.isSourceConnection());
// should succeed, as we're still on source:
- conn2.createStatement().execute("/* ping */ SELECT 1");
+ conn3.createStatement().execute("/* ping */ SELECT 1");
UnreliableSocketFactory.dontDownHost("replica1");
UnreliableSocketFactory.dontDownHost("replica2");
UnreliableSocketFactory.downHost("source");
- try {
- conn2.createStatement().execute("/* ping */ SELECT 1");
- fail("should have failed because source is offline");
- } catch (SQLException e) {
-
- }
+ assertThrows("should have failed because source is offline", SQLException.class, () -> {
+ conn3.createStatement().execute("/* ping */ SELECT 1");
+ return null;
+ });
UnreliableSocketFactory.dontDownHost("source");
- conn2.createStatement().execute("SELECT 1");
+ conn3.createStatement().execute("SELECT 1");
// continue on replica2:
- conn2.setReadOnly(true);
+ conn3.setReadOnly(true);
// should succeed, as replica2 is up:
- conn2.createStatement().execute("/* ping */ SELECT 1");
+ conn3.createStatement().execute("/* ping */ SELECT 1");
UnreliableSocketFactory.downHost("replica2");
- try {
- conn2.createStatement().execute("/* ping */ SELECT 1");
- fail("should have failed because replica2 is offline and the active chosen connection.");
- } catch (SQLException e) {
- }
+ assertThrows("should have failed because replica2 is offline and the active chosen connection.", SQLException.class, () -> {
+ conn3.createStatement().execute("/* ping */ SELECT 1");
+ return null;
+ });
- conn2.close();
+ conn3.close();
}
protected int testServerPrepStmtDeadlockCounter = 0;
@@ -5206,6 +4810,8 @@ public void testBug68400() throws Exception {
this.stmt.executeUpdate("insert into testBug68400 values ('" + s1 + "')");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
props.setProperty(PropertyKey.connectionAttributes.getKeyName(), "testBug68400:true");
@@ -5360,6 +4966,8 @@ public void testBug17251955() throws Exception {
String url = "jdbc:mysql://" + getEncodedHostPortPairFromTestsuiteUrl();
try {
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
c1 = getConnectionWithProps(props);
st1 = c1.createStatement();
@@ -5368,6 +4976,8 @@ public void testBug17251955() throws Exception {
st1.execute("grant all on `\u30C6\u30B9\u30C8\u30C6\u30B9\u30C8`.* to '\u30C6\u30B9\u30C8\u30C6\u30B9\u30C8'@'%'");
props = getHostFreePropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.USER.getKeyName(), "\u30C6\u30B9\u30C8\u30C6\u30B9\u30C8\u30C6\u30B9\u30C8");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "msandbox");
props.remove(PropertyKey.DBNAME.getKeyName());
@@ -5378,6 +4988,7 @@ public void testBug17251955() throws Exception {
} catch (SQLException e) {
assertFalse(e.getCause() instanceof java.lang.ArrayIndexOutOfBoundsException, "e.getCause() instanceof java.lang.ArrayIndexOutOfBoundsException");
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
props.setProperty(PropertyKey.USER.getKeyName(), "\u30C6\u30B9\u30C8\u30C6\u30B9\u30C8");
c2 = DriverManager.getConnection(url + "/\u30C6\u30B9\u30C8\u30C6\u30B9\u30C8", props);
this.rs = c2.createStatement().executeQuery("select 1");
@@ -5407,6 +5018,8 @@ public void testBug69506() throws Exception {
MysqlXADataSource dataSource = new MysqlXADataSource();
dataSource.setUrl(dbUrl);
+ dataSource.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ dataSource.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
XAConnection testXAConn1 = dataSource.getXAConnection();
XAConnection testXAConn2 = dataSource.getXAConnection();
@@ -5438,7 +5051,11 @@ public void testBug69746() throws Exception {
/*
* Test explicit closes
*/
- testConnection = getConnectionWithProps("dontTrackOpenResources=true");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.dontTrackOpenResources.getKeyName(), "true");
+ testConnection = getConnectionWithProps(props);
testStatement = testConnection.createStatement();
testResultSet = testStatement.executeQuery("SELECT 1");
@@ -5471,7 +5088,7 @@ public void testBug69746() throws Exception {
createProcedure("testBug69746_proc", "() BEGIN SELECT 1; SELECT 2; SELECT 3; END");
createTable("testBug69746_tbl", "(fld1 INT NOT NULL AUTO_INCREMENT, fld2 INT, PRIMARY KEY(fld1))");
- testConnection = getConnectionWithProps("dontTrackOpenResources=true");
+ testConnection = getConnectionWithProps(props);
testStatement = testConnection.createStatement();
testResultSet = testStatement.executeQuery("SELECT 1");
@@ -5543,89 +5160,88 @@ private boolean isResultSetClosedForTestBug69746(ResultSet resultSet) {
}
/**
- * This test requires additional server instance configured withm default-authentication-plugin=sha256_password and RSA encryption enabled.
- *
- * To run this test please add this variable to ant call:
- * -Dcom.mysql.cj.testsuite.url.openssl=jdbc:mysql://localhost:3307/test?user=root&password=pwd
+ * Test for sha256_password long data exchange.
*
* @throws Exception
*/
@Test
public void testLongAuthResponsePayload() throws Exception {
- NativeSession sha256Sess;
- if (this.sha256Conn != null && (sha256Sess = (NativeSession) ((JdbcConnection) this.sha256Conn).getSession()).versionMeetsMinimum(5, 6, 6)) {
- Properties props = new Properties();
- props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ NativeSession testSess;
+ assumeTrue((testSess = (NativeSession) ((MysqlConnection) this.conn).getSession()).versionMeetsMinimum(5, 6, 6), "Requires MySQL 5.6.6+.");
+ assumeTrue(pluginIsActive(this.stmt, "sha256_password"), "sha256_password required to run this test");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+ assumeTrue(supportsTestSha256PasswordKeys(this.stmt),
+ "This test requires the server configured with RSA keys from ConnectorJ/src/test/config/ssl-test-certs");
- // check that sha256_password plugin is available
- if (!pluginIsActive(this.sha256Stmt, "sha256_password")) {
- fail("sha256_password required to run this test");
- }
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
+ try {
+ // create user with long password and sha256_password auth
+ String pwd = testSess.versionMeetsMinimum(8, 0, 4) || testSess.versionMeetsMinimum(5, 7, 21) && !testSess.versionMeetsMinimum(8, 0, 0)
+ || testSess.versionMeetsMinimum(5, 6, 39) && !testSess.versionMeetsMinimum(5, 7, 0)
+ ? "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
+ : "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee"
+ + "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee"
+ + "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee";
+
+ if (!testSess.versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
+ }
+ createUser(this.stmt, "'wl6134user'@'%'", "identified WITH sha256_password");
+ this.stmt.executeUpdate("grant all on *.* to 'wl6134user'@'%'");
+ if (!testSess.versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords= 2");
+ this.stmt.executeUpdate("SET SESSION old_passwords= 2");
+ }
+ this.stmt.executeUpdate(
+ ((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl6134user'@'%' IDENTIFIED BY '" + pwd + "'"
+ : "set password for 'wl6134user'@'%' = PASSWORD('" + pwd + "')");
+ this.stmt.executeUpdate("flush privileges");
+
+ this.rs = this.stmt.executeQuery("SELECT plugin FROM mysql.user WHERE user='wl6134user'");
+ assertTrue(this.rs.next());
+ assumeTrue("sha256_password".equals(this.rs.getString(1)), "This test requires the server configured with default sha256_password plugin");
+
+ props.setProperty(PropertyKey.USER.getKeyName(), "wl6134user");
+ props.setProperty(PropertyKey.PASSWORD.getKeyName(), pwd);
+ props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ Connection testConn2 = null;
try {
- // create user with long password and sha256_password auth
- String pwd = sha256Sess.versionMeetsMinimum(8, 0, 4) || sha256Sess.versionMeetsMinimum(5, 7, 21) && !sha256Sess.versionMeetsMinimum(8, 0, 0)
- || sha256Sess.versionMeetsMinimum(5, 6, 39) && !sha256Sess.versionMeetsMinimum(5, 7, 0)
- ? "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
- : "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee"
- + "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee"
- + "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeaaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee";
-
- if (!sha256Sess.versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
- }
- createUser(this.sha256Stmt, "'wl6134user'@'%'", "identified WITH sha256_password");
- this.sha256Stmt.executeUpdate("grant all on *.* to 'wl6134user'@'%'");
- if (!sha256Sess.versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords= 2");
- this.sha256Stmt.executeUpdate("SET SESSION old_passwords= 2");
+ testConn2 = DriverManager.getConnection(dbUrl, props);
+ fail("SQLException expected due to password is too long for RSA encryption");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().startsWith("Data must not be longer than"));
+ } finally {
+ if (testConn2 != null) {
+ testConn2.close();
}
- this.sha256Stmt.executeUpdate(((MysqlConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 7, 6)
- ? "ALTER USER 'wl6134user'@'%' IDENTIFIED BY '" + pwd + "'"
- : "set password for 'wl6134user'@'%' = PASSWORD('" + pwd + "')");
- this.sha256Stmt.executeUpdate("flush privileges");
+ }
- props.setProperty(PropertyKey.USER.getKeyName(), "wl6134user");
- props.setProperty(PropertyKey.PASSWORD.getKeyName(), pwd);
- props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ try {
+ String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
+ System.setProperty("javax.net.ssl.keyStore", trustStorePath);
+ System.setProperty("javax.net.ssl.keyStorePassword", "password");
+ System.setProperty("javax.net.ssl.trustStore", trustStorePath);
+ System.setProperty("javax.net.ssl.trustStorePassword", "password");
- Connection testConn = null;
- try {
- testConn = DriverManager.getConnection(sha256Url, props);
- fail("SQLException expected due to password is too long for RSA encryption");
- } catch (Exception e) {
- assertTrue(e.getMessage().startsWith("Data must not be longer than"));
- } finally {
- if (testConn != null) {
- testConn.close();
- }
- }
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ assertCurrentUser(dbUrl, props, "wl6134user", true);
- try {
- String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
- System.setProperty("javax.net.ssl.keyStore", trustStorePath);
- System.setProperty("javax.net.ssl.keyStorePassword", "password");
- System.setProperty("javax.net.ssl.trustStore", trustStorePath);
- System.setProperty("javax.net.ssl.trustStorePassword", "password");
-
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.verifyServerCertificate.getKeyName(), "false");
- assertCurrentUser(sha256Url, props, "wl6134user", true);
-
- } catch (Exception e) {
- throw e;
- } finally {
- if (testConn != null) {
- testConn.close();
- }
- }
+ } catch (Exception e) {
+ throw e;
} finally {
- if (!sha256Sess.versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
+ if (testConn2 != null) {
+ testConn2.close();
}
}
+ } finally {
+ if (!testSess.versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
+ }
}
}
@@ -5641,11 +5257,17 @@ public void testBug69452() throws Exception {
JdbcConnection connWithMemProps;
long[] memMultiplier = new long[] { 1024, 1024 * 1024, 1024 * 1024 * 1024 };
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
for (int i = 0; i < testMemUnits.length; i++) {
for (int j = 0; j < testMemUnits[i].length; j++) {
// testing with memory values under 2GB because higher values aren't supported.
- connWithMemProps = (com.mysql.cj.jdbc.JdbcConnection) getConnectionWithProps(
- String.format("blobSendChunkSize=1.2%1$s,largeRowSizeThreshold=1.4%1$s,locatorFetchBufferSize=1.6%1$s", testMemUnits[i][j]));
+ props.setProperty(PropertyKey.blobSendChunkSize.getKeyName(), String.format("1.2%1$s", testMemUnits[i][j]));
+ props.setProperty(PropertyKey.largeRowSizeThreshold.getKeyName(), String.format("1.4%1$s", testMemUnits[i][j]));
+ props.setProperty(PropertyKey.locatorFetchBufferSize.getKeyName(), String.format("1.6%1$s", testMemUnits[i][j]));
+ connWithMemProps = (com.mysql.cj.jdbc.JdbcConnection) getConnectionWithProps(props);
// test values of property 'blobSendChunkSize'
assertEquals((int) (memMultiplier[i] * 1.2),
@@ -5679,17 +5301,24 @@ public void testBug69452() throws Exception {
public void testBug69777() throws Exception {
final int maxPacketSizeThreshold = 8203; // ServerPreparedStatement.BLOB_STREAM_READ_BUF_SIZE + 11
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
// test maxAllowedPacket below threshold and useServerPrepStmts=true
+ props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "true");
+ props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "" + (maxPacketSizeThreshold - 1));
assertThrows(SQLException.class, "Connection setting too low for 'maxAllowedPacket'.*", new Callable() {
public Void call() throws Exception {
- getConnectionWithProps("useServerPrepStmts=true,maxAllowedPacket=" + (maxPacketSizeThreshold - 1)).close();
+ getConnectionWithProps(props).close();
return null;
}
});
+ props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "" + maxPacketSizeThreshold);
assertThrows(SQLException.class, "Connection setting too low for 'maxAllowedPacket'.*", new Callable() {
public Void call() throws Exception {
- getConnectionWithProps("useServerPrepStmts=true,maxAllowedPacket=" + maxPacketSizeThreshold).close();
+ getConnectionWithProps(props).close();
return null;
}
});
@@ -5697,16 +5326,21 @@ public Void call() throws Exception {
// the following instructions should execute without any problem
// test maxAllowedPacket above threshold and useServerPrepStmts=true
- getConnectionWithProps("useServerPrepStmts=true,maxAllowedPacket=" + (maxPacketSizeThreshold + 1)).close();
+ props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "" + (maxPacketSizeThreshold + 1));
+ getConnectionWithProps(props).close();
// test maxAllowedPacket below threshold and useServerPrepStmts=false
- getConnectionWithProps("useServerPrepStmts=false,maxAllowedPacket=" + (maxPacketSizeThreshold - 1)).close();
+ props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "false");
+ props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "" + (maxPacketSizeThreshold - 1));
+ getConnectionWithProps(props).close();
// test maxAllowedPacket on threshold and useServerPrepStmts=false
- getConnectionWithProps("useServerPrepStmts=false,maxAllowedPacket=" + maxPacketSizeThreshold).close();
+ props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "" + maxPacketSizeThreshold);
+ getConnectionWithProps(props).close();
// test maxAllowedPacket above threshold and useServerPrepStmts=false
- getConnectionWithProps("useServerPrepStmts=false,maxAllowedPacket=" + (maxPacketSizeThreshold + 1)).close();
+ props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "" + (maxPacketSizeThreshold + 1));
+ getConnectionWithProps(props).close();
}
/**
@@ -5816,58 +5450,16 @@ public Connection call() throws Exception {
}
}
- /**
- * Tests fix for Bug#71038, Add an option for custom collations detection
- *
- * @throws Exception
- */
- @Test
- public void testBug71038() throws Exception {
- Properties p = new Properties();
- p.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "false");
- p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug71038QueryInterceptor.class.getName());
-
- JdbcConnection c = (JdbcConnection) getConnectionWithProps(p);
- Bug71038QueryInterceptor si = (Bug71038QueryInterceptor) c.getQueryInterceptorsInstances().get(0);
- assertTrue(si.cnt == 0, "SHOW COLLATION was issued when detectCustomCollations=false");
- c.close();
-
- p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true");
- p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug71038QueryInterceptor.class.getName());
-
- c = (JdbcConnection) getConnectionWithProps(p);
- si = (Bug71038QueryInterceptor) c.getQueryInterceptorsInstances().get(0);
- assertTrue(si.cnt > 0, "SHOW COLLATION wasn't issued when detectCustomCollations=true");
- c.close();
- }
-
- /**
- * Counts the number of issued "SHOW COLLATION" statements.
- */
- public static class Bug71038QueryInterceptor extends BaseQueryInterceptor {
- int cnt = 0;
-
- @Override
- public M preProcess(M queryPacket) {
- String sql = StringUtils.toString(queryPacket.getByteBuffer(), 1, (queryPacket.getPosition() - 1));
- if (sql.contains("SHOW COLLATION")) {
- this.cnt++;
- }
- return null;
- }
- }
-
/**
* Internal method for tests to get a replication connection with a
* single source host to the test URL.
*
* @param sourceHost
+ * @param props
* @return a replication connection
* @throws Exception
*/
- private ReplicationConnection getTestReplicationConnectionNoReplicas(String sourceHost) throws Exception {
- Properties props = getHostFreePropertiesFromTestsuiteUrl();
+ private ReplicationConnection getTestReplicationConnectionNoReplicas(String sourceHost, Properties props) throws Exception {
List sourceHosts = new ArrayList<>();
sourceHosts.add(mainConnectionUrl.getHostOrSpawnIsolated(sourceHost));
List replicaHosts = new ArrayList<>(); // empty
@@ -5888,8 +5480,14 @@ private ReplicationConnection getTestReplicationConnectionNoReplicas(String sour
@Test
public void testReplicationConnectionNoReplicasRemainOnSource() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
String sourceHost = props.getProperty(PropertyKey.HOST.getKeyName()) + ":" + props.getProperty(PropertyKey.PORT.getKeyName());
- ReplicationConnection replConn = getTestReplicationConnectionNoReplicas(sourceHost);
+
+ Properties props2 = getHostFreePropertiesFromTestsuiteUrl();
+ props2.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props2.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ ReplicationConnection replConn = getTestReplicationConnectionNoReplicas(sourceHost, props2);
Statement s = replConn.createStatement();
ResultSet rs1 = s.executeQuery("select CONNECTION_ID()");
assertTrue(rs1.next());
@@ -5913,8 +5511,14 @@ public void testReplicationConnectionNoReplicasBasics() throws Exception {
// create a replication connection with only a source, get the
// connection id for later use
Properties props = getPropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
String sourceHost = props.getProperty(PropertyKey.HOST.getKeyName()) + ":" + props.getProperty(PropertyKey.PORT.getKeyName());
- ReplicationConnection replConn = getTestReplicationConnectionNoReplicas(sourceHost);
+
+ Properties props2 = getHostFreePropertiesFromTestsuiteUrl();
+ props2.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props2.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ ReplicationConnection replConn = getTestReplicationConnectionNoReplicas(sourceHost, props2);
replConn.setAutoCommit(false);
Statement s = replConn.createStatement();
ResultSet rs1 = s.executeQuery("select CONNECTION_ID()");
@@ -5993,8 +5597,12 @@ public void testReplicationConnectionNoReplicasBasics() throws Exception {
public void testBug71850() throws Exception {
assertThrows(Exception.class, "ExceptionInterceptor.init\\(\\) called 1 time\\(s\\)", new Callable() {
public Void call() throws Exception {
- getConnectionWithProps(
- "exceptionInterceptors=testsuite.regression.ConnectionRegressionTest$TestBug71850ExceptionInterceptor," + "user=unexistent_user");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.exceptionInterceptors.getKeyName(), TestBug71850ExceptionInterceptor.class.getName());
+ props.setProperty(PropertyKey.USER.getKeyName(), "unexistent_user");
+ getConnectionWithProps(props);
return null;
}
});
@@ -6026,6 +5634,8 @@ public SQLException interceptException(Exception sqlEx) {
public void testBug67803() throws Exception {
MysqlXADataSource dataSource = new MysqlXADataSource();
dataSource.setUrl(dbUrl);
+ dataSource.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ dataSource.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
dataSource.getProperty(PropertyKey.useCursorFetch).setValue(true);
dataSource.getProperty(PropertyKey.defaultFetchSize).setValue(50);
dataSource.getProperty(PropertyKey.useServerPrepStmts).setValue(true);
@@ -6057,46 +5667,6 @@ public SQLException interceptException(Exception sqlEx) {
}
}
- /**
- * Test for Bug#72712 - SET NAMES issued unnecessarily.
- *
- * Using a statement interceptor, ensure that SET NAMES is not called if the encoding requested by the client application matches that of
- * character_set_server.
- *
- * Also test that character_set_results is not set unnecessarily.
- *
- * @throws Exception
- */
- @Test
- public void testBug72712() throws Exception {
- // this test is only run when character_set_server=latin1
- if (!((MysqlConnection) this.conn).getSession().getServerSession().getServerVariable("character_set_server").equals("latin1")) {
- return;
- }
-
- Properties p = new Properties();
- p.setProperty(PropertyKey.characterEncoding.getKeyName(), "cp1252");
- p.setProperty(PropertyKey.characterSetResults.getKeyName(), "cp1252");
- p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug72712QueryInterceptor.class.getName());
-
- getConnectionWithProps(p);
- // exception will be thrown from the statement interceptor if any SET statements are issued
- }
-
- /**
- * Statement interceptor used to implement preceding test.
- */
- public static class Bug72712QueryInterceptor extends BaseQueryInterceptor {
- @Override
- public T preProcess(Supplier str, Query interceptedQuery) {
- String sql = str.get();
- if (sql.contains("SET NAMES") || sql.contains("character_set_results") && !(sql.contains("SHOW VARIABLES") || sql.contains("SELECT @@"))) {
- throw ExceptionFactory.createException("Wrongt statement issued: " + sql);
- }
- return null;
- }
- }
-
/**
* Test for Bug#62577 - XA connection fails with ClassCastException
*
@@ -6105,6 +5675,8 @@ public T preProcess(Supplier str, Query intercepte
@Test
public void testBug62577() throws Exception {
Properties props = getHostFreePropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
String hostSpec = getEncodedHostPortPairFromTestsuiteUrl();
String database = props.getProperty(PropertyKey.DBNAME.getKeyName());
props.remove(PropertyKey.DBNAME.getKeyName());
@@ -6145,94 +5717,87 @@ private void testBug62577TestUrl(String url) throws Exception {
/**
* Test fix for Bug#18869381 - CHANGEUSER() FOR SHA USER RESULTS IN NULLPOINTEREXCEPTION
*
- * This test requires additional server instance configured with default-authentication-plugin=sha256_password and RSA encryption enabled.
- *
- * To run this test please add this variable to ant call:
- * -Dcom.mysql.cj.testsuite.url.openssl=jdbc:mysql://localhost:3307/test?user=root&password=pwd
- *
* @throws Exception
*/
@Test
public void testBug18869381() throws Exception {
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 6, 6)) {
-
- if (!pluginIsActive(this.sha256Stmt, "sha256_password")) {
- fail("sha256_password required to run this test");
- }
+ assumeTrue(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 6, 6), "Requires MySQL 5.6.6+.");
+ assumeTrue(pluginIsActive(this.stmt, "sha256_password"), "sha256_password plugin required to run this test");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
- try {
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
- }
- createUser(this.sha256Stmt, "'bug18869381user1'@'%'", "identified WITH sha256_password");
- this.sha256Stmt.executeUpdate("grant all on *.* to 'bug18869381user1'@'%'");
- createUser(this.sha256Stmt, "'bug18869381user2'@'%'", "identified WITH sha256_password");
- this.sha256Stmt.executeUpdate("grant all on *.* to 'bug18869381user2'@'%'");
- createUser(this.sha256Stmt, "'bug18869381user3'@'%'", "identified WITH mysql_native_password");
- this.sha256Stmt.executeUpdate("grant all on *.* to 'bug18869381user3'@'%'");
- this.sha256Stmt.executeUpdate(
- ((MysqlConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'bug18869381user3'@'%' IDENTIFIED BY 'pwd3'"
- : "set password for 'bug18869381user3'@'%' = PASSWORD('pwd3')");
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords= 2");
- this.sha256Stmt.executeUpdate("SET SESSION old_passwords= 2");
- }
- this.sha256Stmt.executeUpdate(((MysqlConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 7, 6)
- ? "ALTER USER 'bug18869381user1'@'%' IDENTIFIED BY 'LongLongLongLongLongLongLongLongLongLongLongLongPwd1'"
- : "set password for 'bug18869381user1'@'%' = PASSWORD('LongLongLongLongLongLongLongLongLongLongLongLongPwd1')");
- this.sha256Stmt.executeUpdate(
- ((MysqlConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'bug18869381user2'@'%' IDENTIFIED BY 'pwd2'"
- : "set password for 'bug18869381user2'@'%' = PASSWORD('pwd2')");
- this.sha256Stmt.executeUpdate("flush privileges");
+ try {
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
+ }
+ createUser(this.stmt, "'bug18869381user1'@'%'", "identified WITH sha256_password");
+ this.stmt.executeUpdate("grant all on *.* to 'bug18869381user1'@'%'");
+ createUser(this.stmt, "'bug18869381user2'@'%'", "identified WITH sha256_password");
+ this.stmt.executeUpdate("grant all on *.* to 'bug18869381user2'@'%'");
+ createUser(this.stmt, "'bug18869381user3'@'%'", "identified WITH mysql_native_password");
+ this.stmt.executeUpdate("grant all on *.* to 'bug18869381user3'@'%'");
+ this.stmt.executeUpdate(
+ ((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'bug18869381user3'@'%' IDENTIFIED BY 'pwd3'"
+ : "set password for 'bug18869381user3'@'%' = PASSWORD('pwd3')");
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords= 2");
+ this.stmt.executeUpdate("SET SESSION old_passwords= 2");
+ }
+ this.stmt.executeUpdate(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6)
+ ? "ALTER USER 'bug18869381user1'@'%' IDENTIFIED BY 'LongLongLongLongLongLongLongLongLongLongLongLongPwd1'"
+ : "set password for 'bug18869381user1'@'%' = PASSWORD('LongLongLongLongLongLongLongLongLongLongLongLongPwd1')");
+ this.stmt.executeUpdate(
+ ((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'bug18869381user2'@'%' IDENTIFIED BY 'pwd2'"
+ : "set password for 'bug18869381user2'@'%' = PASSWORD('pwd2')");
+ this.stmt.executeUpdate("flush privileges");
- Properties props = new Properties();
- props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
- props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
- testBug18869381WithProperties(props);
- props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
- testBug18869381WithProperties(props);
+ props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
+ testBug18869381WithProperties(dbUrl, props);
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
+ testBug18869381WithProperties(dbUrl, props);
- props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
- props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
- testBug18869381WithProperties(props);
- props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
- testBug18869381WithProperties(props);
+ props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
+ testBug18869381WithProperties(dbUrl, props);
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
+ testBug18869381WithProperties(dbUrl, props);
- props.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
- testBug18869381WithProperties(props);
- props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
- testBug18869381WithProperties(props);
+ props.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
+ testBug18869381WithProperties(dbUrl, props);
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
+ testBug18869381WithProperties(dbUrl, props);
- String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
- System.setProperty("javax.net.ssl.keyStore", trustStorePath);
- System.setProperty("javax.net.ssl.keyStorePassword", "password");
- System.setProperty("javax.net.ssl.trustStore", trustStorePath);
- System.setProperty("javax.net.ssl.trustStorePassword", "password");
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
- testBug18869381WithProperties(props);
- props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
- testBug18869381WithProperties(props);
+ String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
+ System.setProperty("javax.net.ssl.keyStore", trustStorePath);
+ System.setProperty("javax.net.ssl.keyStorePassword", "password");
+ System.setProperty("javax.net.ssl.trustStore", trustStorePath);
+ System.setProperty("javax.net.ssl.trustStorePassword", "password");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "false");
+ testBug18869381WithProperties(dbUrl, props);
+ props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
+ testBug18869381WithProperties(dbUrl, props);
- } finally {
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
- }
+ } finally {
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
}
}
}
@Test
- private void testBug18869381WithProperties(Properties props) throws Exception {
+ private void testBug18869381WithProperties(String url, Properties props) throws Exception {
Connection testConn = null;
Statement testSt = null;
ResultSet testRs = null;
try {
- testConn = getConnectionWithProps(sha256Url, props);
+ testConn = getConnectionWithProps(url, props);
((JdbcConnection) testConn).changeUser("bug18869381user1", "LongLongLongLongLongLongLongLongLongLongLongLongPwd1");
testSt = testConn.createStatement();
@@ -6271,17 +5836,23 @@ private void testBug18869381WithProperties(Properties props) throws Exception {
*/
@Test
public void testBug73053() throws Exception {
+ assumeFalse(isServerRunningOnWindows(), "This test requires the server running on Linux.");
+
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
/*
* Test reported issue using a Socket implementation that simulates the buggy behavior.
*/
try {
- Connection testConn = getConnectionWithProps(
- "sslMode=DISABLED,socketFactory=testsuite.regression.ConnectionRegressionTest$TestBug73053SocketFactory");
+ props.setProperty(PropertyKey.socketFactory.getKeyName(), TestBug73053SocketFactory.class.getName());
+ Connection testConn = getConnectionWithProps(props);
Statement testStmt = testConn.createStatement();
this.rs = testStmt.executeQuery("SELECT 1");
testStmt.close();
testConn.close();
} catch (SQLException e) {
+ e.printStackTrace();
fail("No SQLException should be thrown.");
}
@@ -6291,7 +5862,8 @@ public void testBug73053() throws Exception {
* the statement, thus calling MysqlIO.clearInputStream() and effectively discard unread data.
*/
try {
- Connection testConn = getConnectionWithProps("allowMultiQueries=true");
+ props.setProperty(PropertyKey.allowMultiQueries.getKeyName(), "true");
+ Connection testConn = getConnectionWithProps(props);
Statement testStmt = testConn.createStatement();
testStmt.setFetchSize(Integer.MIN_VALUE); // set for streaming results
@@ -6322,7 +5894,11 @@ public void testBug73053() throws Exception {
public void run() {
try {
// set socketTimeout so this thread doesn't hang if no exception is thrown after killing the connection at server side
- Connection testConn = getConnectionWithProps("socketTimeout=" + timeout);
+ Properties props2 = new Properties();
+ props2.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props2.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props2.setProperty(PropertyKey.socketTimeout.getKeyName(), "" + timeout);
+ Connection testConn = getConnectionWithProps(props2);
Statement testStmt = testConn.createStatement();
try {
testStmt.execute(query);
@@ -6358,9 +5934,7 @@ public void run() {
elapsedTime = System.currentTimeMillis() - timestamp;
// allow it 10% more time to reach the socketTimeout threshold
- if (elapsedTime > timeout * 1.1) {
- fail("Failed killing the connection at server side.");
- }
+ assertFalse(elapsedTime > timeout * 1.1, "Failed killing the connection at server side.");
}
} catch (SQLException e) {
fail("No SQLException should be thrown.");
@@ -6694,9 +6268,8 @@ public String toString() {
*/
@Test
public void testBug19354014() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7), "MySQL 5.7.7+ is required to run this test.");
+
Connection con = null;
createUser("'bug19354014user'@'%'", "identified WITH mysql_native_password");
this.stmt.executeUpdate("grant all on *.* to 'bug19354014user'@'%'");
@@ -6706,6 +6279,8 @@ public void testBug19354014() throws Exception {
try {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useCompression.getKeyName(), "true");
con = getConnectionWithProps(props);
@@ -6727,6 +6302,8 @@ public void testBug19354014() throws Exception {
@Test
public void testBug75168() throws Exception {
final Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.loadBalanceExceptionChecker.getKeyName(), Bug75168LoadBalanceExceptionChecker.class.getName());
props.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug75168QueryInterceptor.class.getName());
@@ -6797,9 +6374,7 @@ public QueryInterceptor init(MysqlConnection conn, Properties props, Log log) {
@Override
public void destroy() {
this.connection = null;
- if (previousConnection == null) {
- fail("Test testBug75168 didn't run as expected.");
- }
+ assertNotNull(previousConnection, "Test testBug75168 didn't run as expected.");
}
@Override
@@ -6924,9 +6499,13 @@ private void testBug71084AssertCase(Properties connProps, String clientTZ, Strin
*/
@Test
public void testBug20685022() throws Exception {
- if (!isCommunityEdition()) {
- return;
- }
+ assumeTrue(isCommunityEdition(), "Commercial server version is required to run this test.");
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
final Properties props = new Properties();
@@ -6934,9 +6513,7 @@ public void testBug20685022() throws Exception {
* case 1: non verifying server certificate
*/
props.clear();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.verifyServerCertificate.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
getConnectionWithProps(props);
@@ -6944,9 +6521,7 @@ public void testBug20685022() throws Exception {
* case 2: verifying server certificate using key store provided by connection properties
*/
props.clear();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.verifyServerCertificate.getKeyName(), "true");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.VERIFY_CA.name());
props.setProperty(PropertyKey.trustCertificateKeyStoreUrl.getKeyName(), "file:src/test/config/ssl-test-certs/ca-truststore");
props.setProperty(PropertyKey.trustCertificateKeyStoreType.getKeyName(), "JKS");
props.setProperty(PropertyKey.trustCertificateKeyStorePassword.getKeyName(), "password");
@@ -6957,9 +6532,7 @@ public void testBug20685022() throws Exception {
* case 3: verifying server certificate using key store provided by system properties
*/
props.clear();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.verifyServerCertificate.getKeyName(), "true");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.VERIFY_CA.name());
String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
System.setProperty("javax.net.ssl.keyStore", trustStorePath);
@@ -6979,13 +6552,18 @@ public void testBug20685022() throws Exception {
public void testBug75592() throws Exception {
if (versionMeetsMinimum(5, 0, 3)) {
- JdbcConnection con = (JdbcConnection) getConnectionWithProps("queryInterceptors=" + Bug75592QueryInterceptor.class.getName());
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug75592QueryInterceptor.class.getName());
+ JdbcConnection con = (JdbcConnection) getConnectionWithProps(props);
// reference values
Map serverVariables = new HashMap<>();
this.rs = con.createStatement().executeQuery("SHOW VARIABLES");
while (this.rs.next()) {
- serverVariables.put(this.rs.getString(1), this.rs.getString(2));
+ String val = this.rs.getString(2);
+ serverVariables.put(this.rs.getString(1), "utf8mb3".equals(val) ? "utf8" : val);
}
// fix the renaming of "tx_isolation" to "transaction_isolation" that is made in NativeSession.loadServerVariables().
@@ -6996,15 +6574,17 @@ public void testBug75592() throws Exception {
// check values from "select @@var..."
assertEquals(serverVariables.get("auto_increment_increment"), session.getServerSession().getServerVariable("auto_increment_increment"));
- assertEquals(serverVariables.get("character_set_client"), session.getServerSession().getServerVariable("character_set_client"));
- assertEquals(serverVariables.get("character_set_connection"), session.getServerSession().getServerVariable("character_set_connection"));
+ assertEquals(serverVariables.get(CharsetSettings.CHARACTER_SET_CLIENT),
+ session.getServerSession().getServerVariable(CharsetSettings.CHARACTER_SET_CLIENT));
+ assertEquals(serverVariables.get(CharsetSettings.CHARACTER_SET_CONNECTION),
+ session.getServerSession().getServerVariable(CharsetSettings.CHARACTER_SET_CONNECTION));
// we override character_set_results sometimes when configuring client charsets, thus need to check against actual value
- if (session.getServerSession().getServerVariable(ServerSession.LOCAL_CHARACTER_SET_RESULTS) == null) {
- assertEquals("", serverVariables.get("character_set_results"));
+ if (session.getServerSession().getServerVariable(CharsetSettings.CHARACTER_SET_RESULTS) == null) {
+ assertEquals("", serverVariables.get(CharsetSettings.CHARACTER_SET_RESULTS));
} else {
- assertEquals(serverVariables.get("character_set_results"),
- session.getServerSession().getServerVariable(ServerSession.LOCAL_CHARACTER_SET_RESULTS));
+ assertEquals(serverVariables.get(CharsetSettings.CHARACTER_SET_RESULTS),
+ session.getServerSession().getServerVariable(CharsetSettings.CHARACTER_SET_RESULTS));
}
assertEquals(serverVariables.get("character_set_server"), session.getServerSession().getServerVariable("character_set_server"));
@@ -7061,12 +6641,16 @@ public void testBug62452() throws Exception {
MysqlConnectionPoolDataSource pds = new MysqlConnectionPoolDataSource();
pds.setUrl(dbUrl);
+ pds.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ pds.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
con = pds.getPooledConnection();
assertTrue(con instanceof MysqlPooledConnection);
testBug62452WithConnection(con);
MysqlXADataSource xads = new MysqlXADataSource();
xads.setUrl(dbUrl);
+ xads.getStringProperty(PropertyKey.sslMode.getKeyName()).setValue("DISABLED");
+ xads.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName()).setValue(true);
xads.getProperty(PropertyKey.pinGlobalTxToPhysicalConnection).setValue(false);
con = xads.getXAConnection();
@@ -7092,138 +6676,130 @@ private void testBug62452WithConnection(PooledConnection con) throws Exception {
/**
* Tests fix for BUG#20825727 - CONNECT FAILURE WHEN TRY TO CONNECT SHA USER WITH DIFFERENT CHARSET.
*
- * This test runs through all authentication plugins when one of the following server requirements is met:
- * 1. Default connection string points to a server configured with both SSL *and* RSA encryption.
- * or
- * 2. Default connection string points to a server configured with SSL enabled but no RSA encryption *and* the property
- * com.mysql.cj.testsuite.url.openssl points to an additional server configured with
- * default-authentication-plugin=sha256_password and RSA encryption.
- *
- * If none of the servers has SSL and RSA encryption enabled then only 'mysql_native_password' and 'mysql_old_password' plugins are tested.
- *
* @throws Exception
*/
@Test
public void testBug20825727() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7) || isSysPropDefined(PropertyDefinitions.SYSP_testsuite_no_server_testsuite)) {
- return;
- }
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
- final String[] testDbUrls;
Properties props = new Properties();
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- if (this.sha256Conn != null && ((MysqlConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 5, 7)) {
- testDbUrls = new String[] { BaseTestCase.dbUrl, sha256Url };
- } else {
- testDbUrls = new String[] { BaseTestCase.dbUrl };
- }
+ JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(dbUrl, props);
+ Statement testStmt = testConn.createStatement();
- for (String testDbUrl : testDbUrls) {
- JdbcConnection testConn = (JdbcConnection) getConnectionWithProps(testDbUrl, props);
- Statement testStmt = testConn.createStatement();
+ this.rs = testStmt.executeQuery("SELECT @@GLOBAL.HAVE_SSL = 'YES' AS have_ssl");
+ final boolean sslEnabled = this.rs.next() && this.rs.getBoolean(1);
- this.rs = testStmt.executeQuery("SELECT @@GLOBAL.HAVE_SSL = 'YES' AS have_ssl");
- final boolean sslEnabled = this.rs.next() && this.rs.getBoolean(1);
+ this.rs = testStmt.executeQuery("SHOW STATUS LIKE '%Rsa_public_key%'");
+ final boolean rsaEnabled = this.rs.next() && this.rs.getString(1).length() > 0;
- this.rs = testStmt.executeQuery("SHOW STATUS LIKE '%Rsa_public_key%'");
- final boolean rsaEnabled = this.rs.next() && this.rs.getString(1).length() > 0;
+ System.out.println();
+ System.out.println("* Testing URL: " + dbUrl + " [SSL enabled: " + sslEnabled + "] [RSA enabled: " + rsaEnabled + "]");
+ System.out.println("******************************************************************************************************************************"
+ + "*************");
+ System.out.printf("%-25s : %-25s : %s : %-25s : %-18s : %-18s [%s]%n", "Connection Type", "Auth. Plugin", "pwd ", "Encoding Prop.", "Encoding Value",
+ "Server Encoding", "TstRes");
+ System.out.println("------------------------------------------------------------------------------------------------------------------------------"
+ + "-------------");
- System.out.println();
- System.out.println("* Testing URL: " + testDbUrl + " [SSL enabled: " + sslEnabled + "] [RSA enabled: " + rsaEnabled + "]");
- System.out.println("******************************************************************************************************************************"
- + "*************");
- System.out.printf("%-25s : %-25s : %s : %-25s : %-18s : %-18s [%s]%n", "Connection Type", "Auth. Plugin", "pwd ", "Encoding Prop.",
- "Encoding Value", "Server Encoding", "TstRes");
- System.out.println("------------------------------------------------------------------------------------------------------------------------------"
- + "-------------");
-
- boolean clearTextPluginInstalled = false;
- boolean secureAuthChanged = false;
- try {
- String[] plugins;
+ boolean clearTextPluginInstalled = false;
+ boolean secureAuthChanged = false;
+ try {
+ String[] plugins;
+
+ // install cleartext plugin if required
+ this.rs = testStmt.executeQuery(
+ "SELECT (PLUGIN_LIBRARY LIKE 'auth_test_plugin%') FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME='cleartext_plugin_server'");
+ if (!this.rs.next() || !this.rs.getBoolean(1)) {
+ String ext = System.getProperty(PropertyDefinitions.SYSP_os_name).toUpperCase().indexOf("WINDOWS") > -1 ? ".dll" : ".so";
- // install cleartext plugin if required
- this.rs = testStmt.executeQuery(
- "SELECT (PLUGIN_LIBRARY LIKE 'auth_test_plugin%') FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME='cleartext_plugin_server'");
- if (!this.rs.next() || !this.rs.getBoolean(1)) {
- String ext = System.getProperty(PropertyDefinitions.SYSP_os_name).toUpperCase().indexOf("WINDOWS") > -1 ? ".dll" : ".so";
+ try {
testStmt.execute("INSTALL PLUGIN cleartext_plugin_server SONAME 'auth_test_plugin" + ext + "'");
- clearTextPluginInstalled = true;
+ } catch (SQLException e) {
+ if (e.getErrorCode() == MysqlErrorNumbers.ER_CANT_OPEN_LIBRARY) {
+ assumeTrue(false, "This test requires a server installed with the test package.");
+ } else {
+ throw e;
+ }
}
- if (testConn.getSession().versionMeetsMinimum(5, 7, 5)) {
- // mysql_old_password plugin not supported
- plugins = new String[] { "cleartext_plugin_server,-1", "mysql_native_password,0", "sha256_password,2" };
- } else if (testConn.getSession().versionMeetsMinimum(5, 6, 6)) {
- plugins = new String[] { "cleartext_plugin_server,-1", "mysql_native_password,0", "mysql_old_password,1", "sha256_password,2" };
+ clearTextPluginInstalled = true;
+ }
- // temporarily disable --secure-auth mode to allow old format passwords
- testStmt.executeUpdate("SET @current_secure_auth = @@global.secure_auth");
- testStmt.executeUpdate("SET @@global.secure_auth = off");
- secureAuthChanged = true;
- } else {
- // sha256_password plugin not supported
- plugins = new String[] { "cleartext_plugin_server,-1", "mysql_native_password,0", "mysql_old_password,1" };
- }
+ if (testConn.getSession().versionMeetsMinimum(5, 7, 5)) {
+ // mysql_old_password plugin not supported
+ plugins = new String[] { "cleartext_plugin_server,-1", "mysql_native_password,0", "sha256_password,2" };
+ } else if (testConn.getSession().versionMeetsMinimum(5, 6, 6)) {
+ plugins = new String[] { "cleartext_plugin_server,-1", "mysql_native_password,0", "mysql_old_password,1", "sha256_password,2" };
+
+ // temporarily disable --secure-auth mode to allow old format passwords
+ testStmt.executeUpdate("SET @current_secure_auth = @@global.secure_auth");
+ testStmt.executeUpdate("SET @@global.secure_auth = off");
+ secureAuthChanged = true;
+ } else {
+ // sha256_password plugin not supported
+ plugins = new String[] { "cleartext_plugin_server,-1", "mysql_native_password,0", "mysql_old_password,1" };
+ }
- final String simplePwd = "my\tpass word";
- final String complexPwd = "my\tp\u00e4ss w\u263ard";
+ final String simplePwd = "my\tpass word";
+ final String complexPwd = "my\tp\u00e4ss w\u263ard";
- for (String encoding : new String[] { "", "UTF-8", "ISO-8859-1", "US-ASCII" }) {
- for (String plugin : plugins) {
+ for (String encoding : new String[] { "", "UTF-8", "ISO-8859-1", "US-ASCII" }) {
+ for (String plugin : plugins) {
- String pluginName = plugin.split(",")[0];
- int pwdHashingMethod = Integer.parseInt(plugin.split(",")[1]);
+ String pluginName = plugin.split(",")[0];
+ int pwdHashingMethod = Integer.parseInt(plugin.split(",")[1]);
- String testStep = "";
+ String testStep = "";
+ try {
+ testStep = "create user";
+ testBug20825727CreateUser(dbUrl, "testBug20825727", simplePwd, pluginName, pwdHashingMethod);
+ testStep = "login with simple password";
+ testBug20825727TestLogin(dbUrl, testConn.getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue(), sslEnabled,
+ rsaEnabled, "testBug20825727", simplePwd, encoding, pluginName);
+
+ testStep = "change password";
+ testBug20825727ChangePassword(dbUrl, "testBug20825727", complexPwd, pluginName, pwdHashingMethod);
+ testStep = "login with complex password";
+ testBug20825727TestLogin(dbUrl, testConn.getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue(), sslEnabled,
+ rsaEnabled, "testBug20825727", complexPwd, encoding, pluginName);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail("Failed at '" + testStep + "' using encoding '" + encoding + "' and plugin '" + pluginName
+ + "'. See also system output for more details.");
+ } finally {
try {
- testStep = "create user";
- testBug20825727CreateUser(testDbUrl, "testBug20825727", simplePwd, encoding, pluginName, pwdHashingMethod);
- testStep = "login with simple password";
- testBug20825727TestLogin(testDbUrl, testConn.getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue(),
- sslEnabled, rsaEnabled, "testBug20825727", simplePwd, encoding, pluginName);
-
- testStep = "change password";
- testBug20825727ChangePassword(testDbUrl, "testBug20825727", complexPwd, encoding, pluginName, pwdHashingMethod);
- testStep = "login with complex password";
- testBug20825727TestLogin(testDbUrl, testConn.getPropertySet().getStringProperty(PropertyKey.characterEncoding).getValue(),
- sslEnabled, rsaEnabled, "testBug20825727", complexPwd, encoding, pluginName);
- } catch (SQLException e) {
- e.printStackTrace();
- fail("Failed at '" + testStep + "' using encoding '" + encoding + "' and plugin '" + pluginName
- + "'. See also system output for more details.");
- } finally {
- try {
- dropUser(testStmt, "'testBug20825727'@'%'");
- } catch (Exception e) {
- }
+ dropUser(testStmt, "'testBug20825727'@'%'");
+ } catch (Exception e) {
}
}
}
- } finally {
- if (clearTextPluginInstalled) {
- testStmt.executeUpdate("UNINSTALL PLUGIN cleartext_plugin_server");
- }
- if (secureAuthChanged) {
- testStmt.executeUpdate("SET @@global.secure_auth = @current_secure_auth");
- }
-
- testStmt.close();
- testConn.close();
}
+ } finally {
+ if (clearTextPluginInstalled) {
+ testStmt.executeUpdate("UNINSTALL PLUGIN cleartext_plugin_server");
+ }
+ if (secureAuthChanged) {
+ testStmt.executeUpdate("SET @@global.secure_auth = @current_secure_auth");
+ }
+
+ testStmt.close();
+ testConn.close();
}
}
- private void testBug20825727CreateUser(String testDbUrl, String user, String password, String encoding, String pluginName, int pwdHashingMethod)
- throws SQLException {
+ private void testBug20825727CreateUser(String testDbUrl, String user, String password, String pluginName, int pwdHashingMethod) throws SQLException {
JdbcConnection testConn = null;
try {
Properties props = new Properties();
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- if (encoding.length() > 0) {
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), encoding);
- }
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
testConn = (JdbcConnection) getConnectionWithProps(testDbUrl, props);
Statement testStmt = testConn.createStatement();
@@ -7252,15 +6828,12 @@ private void testBug20825727CreateUser(String testDbUrl, String user, String pas
}
}
- private void testBug20825727ChangePassword(String testDbUrl, String user, String password, String encoding, String pluginName, int pwdHashingMethod)
- throws SQLException {
+ private void testBug20825727ChangePassword(String testDbUrl, String user, String password, String pluginName, int pwdHashingMethod) throws SQLException {
JdbcConnection testConn = null;
try {
Properties props = new Properties();
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- if (encoding.length() > 0) {
- props.setProperty(PropertyKey.characterEncoding.getKeyName(), encoding);
- }
+ props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
testConn = (JdbcConnection) getConnectionWithProps(testDbUrl, props);
Statement testStmt = testConn.createStatement();
@@ -7317,8 +6890,7 @@ private void testBug20825727TestLogin(final String testDbUrl, String defaultServ
continue;
}
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
testCaseMsg = "Non-SSL/Non-RSA";
break;
@@ -7330,16 +6902,13 @@ private void testBug20825727TestLogin(final String testDbUrl, String defaultServ
continue;
}
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "false");
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.verifyServerCertificate.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
testCaseMsg = "SSL";
break;
case 3:
/*
* Test with an RSA encryption enabled connection, using public key retrieved from server.
- * Requires additional server instance pointed by 'com.mysql.cj.testsuite.url.openssl'.
* Can't be used with plugin 'cleartext_plugin_server'.
*/
if (pluginName.equals("cleartext_plugin_server") || !rsaEnabled) {
@@ -7352,7 +6921,6 @@ private void testBug20825727TestLogin(final String testDbUrl, String defaultServ
case 4:
/*
* Test with an RSA encryption enabled connection, using public key pointed by the property 'serverRSAPublicKeyFile'.
- * Requires additional server instance pointed by 'com.mysql.cj.testsuite.url.openssl'.
* Can't be used with plugin 'cleartext_plugin_server'.
*/
if (pluginName.equals("cleartext_plugin_server") || !rsaEnabled) {
@@ -7366,13 +6934,8 @@ private void testBug20825727TestLogin(final String testDbUrl, String defaultServ
boolean testShouldPass = true;
if (pwdIsComplex) {
- // if no encoding is specifically defined then our default password encoding ('UTF-8') and server's encoding must coincide
- testShouldPass = encoding.length() > 0 || defaultServerEncoding.equalsIgnoreCase("UTF-8");
-
- if (!testBaseConn.getSession().versionMeetsMinimum(5, 7, 6) && pluginName.equals("cleartext_plugin_server")) {
- // 'cleartext_plugin_server' from servers below version 5.7.6 requires UTF-8 encoding
- testShouldPass = encoding.equals("UTF-8") || (encoding.length() == 0 && defaultServerEncoding.equals("UTF-8"));
- }
+ // if no encoding is specifically defined then our default password encoding is set to server's encoding
+ testShouldPass = encoding.equals("UTF-8") || (encoding.length() == 0 && defaultServerEncoding.equals("UTF-8"));
}
System.out.printf("%-25s : %-25s : %s : %-25s : %-18s : %-18s [%s]%n", testCaseMsg, pluginName, pwdIsComplex ? "cplx" : "smpl", encProp,
@@ -7386,9 +6949,8 @@ private void testBug20825727TestLogin(final String testDbUrl, String defaultServ
this.rs = testStmt.executeQuery("SELECT USER(), CURRENT_USER()");
assertTrue(this.rs.next());
- if (!this.rs.getString(1).startsWith(user) || !this.rs.getString(2).startsWith(user)) {
- fail("Unexpected failure in test case '" + testCaseMsg + "' using encoding '" + encoding + "' in property '" + encProp + "'.");
- }
+ assertFalse(!this.rs.getString(1).startsWith(user) || !this.rs.getString(2).startsWith(user),
+ "Unexpected failure in test case '" + testCaseMsg + "' using encoding '" + encoding + "' in property '" + encProp + "'.");
this.rs.close();
testStmt.close();
} else {
@@ -7417,151 +6979,150 @@ public Void call() throws Exception {
/**
* Tests fix for BUG#75670 - Connection fails with "Public Key Retrieval is not allowed" for native auth.
*
- * Requires additional server instance pointed by com.mysql.cj.testsuite.url.openssl variable configured with default-authentication-plugin=sha256_password
- * and RSA encryption enabled.
+ * Requires the server to be configured with default-authentication-plugin=sha256_password and RSA encryption enabled.
*
* @throws Exception
*/
@Test
public void testBug75670() throws Exception {
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 6, 6)) {
+ assumeTrue(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 6, 6), "Requires MySQL 5.6.6+.");
+ assumeTrue(pluginIsActive(this.stmt, "sha256_password"), "sha256_password plugin required to run this test");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+ assumeTrue(supportsTestSha256PasswordKeys(this.stmt),
+ "This test requires the server configured with RSA keys from ConnectorJ/src/test/config/ssl-test-certs");
- if (!pluginIsActive(this.sha256Stmt, "sha256_password")) {
- fail("sha256_password required to run this test");
+ try {
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
}
- try {
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
+ createUser(this.stmt, "'bug75670user'@'%'", ""); // let --default-authentication-plugin option force sha256_password
+ this.rs = this.stmt.executeQuery("SELECT plugin FROM mysql.user WHERE user='bug75670user'");
+ assertTrue(this.rs.next());
+ assumeTrue("sha256_password".equals(this.rs.getString(1)), "This test requires the server configured with default sha256_password plugin");
+
+ if (((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6)) {
+ createUser(this.stmt, "'bug75670user_mnp'@'%'", "IDENTIFIED WITH mysql_native_password BY 'bug75670user_mnp'");
+ createUser(this.stmt, "'bug75670user_sha'@'%'", "IDENTIFIED WITH sha256_password BY 'bug75670user_sha'");
+ } else {
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.execute("SET @@session.old_passwords = 0");
}
+ createUser(this.stmt, "'bug75670user_mnp'@'%'", "IDENTIFIED WITH mysql_native_password");
+ this.stmt.execute("SET PASSWORD FOR 'bug75670user_mnp'@'%' = PASSWORD('bug75670user_mnp')");
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.execute("SET @@session.old_passwords = 2");
+ }
+ createUser(this.stmt, "'bug75670user_sha'@'%'", "IDENTIFIED WITH sha256_password");
+ this.stmt.execute("SET PASSWORD FOR 'bug75670user_sha'@'%' = PASSWORD('bug75670user_sha')");
+ }
+ this.stmt.execute("GRANT ALL ON *.* TO 'bug75670user_mnp'@'%'");
+ this.stmt.execute("GRANT ALL ON *.* TO 'bug75670user_sha'@'%'");
- createUser(this.sha256Stmt, "'bug75670user'@'%'", ""); // let --default-authentication-plugin option force sha256_password
- this.rs = this.sha256Stmt.executeQuery("SELECT plugin FROM mysql.user WHERE user='bug75670user'");
- assertTrue(this.rs.next());
- assertEquals("sha256_password", this.rs.getString(1), "Wrong default authentication plugin (check test conditions):");
+ System.out.println();
+ System.out.printf("%-25s : %-18s : %-25s : %-25s : %s%n", "DefAuthPlugin", "AllowPubKeyRet", "User", "Passwd", "Test result");
+ System.out.println(
+ "----------------------------------------------------------------------------------------------------" + "------------------------------");
+
+ for (Class> defAuthPlugin : new Class>[] { MysqlNativePasswordPlugin.class, Sha256PasswordPlugin.class }) {
+ for (String user : new String[] { "bug75670user_mnp", "bug75670user_sha" }) {
+ for (String pwd : new String[] { user, "wrong*pwd", "" }) {
+ for (boolean allowPubKeyRetrieval : new boolean[] { true, false }) {
+ final Connection testConn;
+ Statement testStmt;
+
+ boolean expectedPubKeyRetrievalFail = (user.endsWith("_sha")
+ || user.endsWith("_mnp") && defAuthPlugin.equals(Sha256PasswordPlugin.class)) && !allowPubKeyRetrieval && pwd.length() > 0;
+ boolean expectedAccessDeniedFail = !user.equals(pwd);
+ System.out.printf("%-25s : %-18s : %-25s : %-25s : %s%n", defAuthPlugin.getSimpleName(), allowPubKeyRetrieval, user, pwd,
+ expectedPubKeyRetrievalFail ? "Fail [Pub. Key retrieval]" : expectedAccessDeniedFail ? "Fail [Access denied]" : "Ok");
+
+ final Properties props = new Properties();
+ props.setProperty(PropertyKey.USER.getKeyName(), user);
+ props.setProperty(PropertyKey.PASSWORD.getKeyName(), pwd);
+ props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), defAuthPlugin.getName());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), Boolean.toString(allowPubKeyRetrieval));
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+
+ if (expectedPubKeyRetrievalFail) {
+ // connection will fail due to public key retrieval failure
+ assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, props);
+ return null;
+ }
+ });
+
+ } else if (expectedAccessDeniedFail) {
+ // connection will fail due to wrong password
+ assertThrows(SQLException.class, "Access denied for user '" + user + "'@.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, props);
+ return null;
+ }
+ });
- if (((MysqlConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 7, 6)) {
- createUser(this.sha256Stmt, "'bug75670user_mnp'@'%'", "IDENTIFIED WITH mysql_native_password BY 'bug75670user_mnp'");
- createUser(this.sha256Stmt, "'bug75670user_sha'@'%'", "IDENTIFIED WITH sha256_password BY 'bug75670user_sha'");
- } else {
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.execute("SET @@session.old_passwords = 0");
- }
- createUser(this.sha256Stmt, "'bug75670user_mnp'@'%'", "IDENTIFIED WITH mysql_native_password");
- this.sha256Stmt.execute("SET PASSWORD FOR 'bug75670user_mnp'@'%' = PASSWORD('bug75670user_mnp')");
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.execute("SET @@session.old_passwords = 2");
- }
- createUser(this.sha256Stmt, "'bug75670user_sha'@'%'", "IDENTIFIED WITH sha256_password");
- this.sha256Stmt.execute("SET PASSWORD FOR 'bug75670user_sha'@'%' = PASSWORD('bug75670user_sha')");
- }
- this.sha256Stmt.execute("GRANT ALL ON *.* TO 'bug75670user_mnp'@'%'");
- this.sha256Stmt.execute("GRANT ALL ON *.* TO 'bug75670user_sha'@'%'");
+ } else {
+ // connection will succeed
+ testConn = getConnectionWithProps(dbUrl, props);
+ testStmt = testConn.createStatement();
+ this.rs = testStmt.executeQuery("SELECT USER(), CURRENT_USER()");
+ assertTrue(this.rs.next());
+ assertTrue(this.rs.getString(1).startsWith(user));
+ assertTrue(this.rs.getString(2).startsWith(user));
+ this.rs.close();
+ testStmt.close();
+
+ // change user using same credentials will succeed
+ System.out.printf("%25s : %-18s : %-25s : %-25s : %s%n", "| ChangeUser (same)", allowPubKeyRetrieval, user, pwd, "Ok");
+ ((JdbcConnection) testConn).changeUser(user, user);
+ testStmt = testConn.createStatement();
+ this.rs = testStmt.executeQuery("SELECT USER(), CURRENT_USER()");
+ assertTrue(this.rs.next());
+ assertTrue(this.rs.getString(1).startsWith(user));
+ assertTrue(this.rs.getString(2).startsWith(user));
+ this.rs.close();
+ testStmt.close();
- System.out.println();
- System.out.printf("%-25s : %-18s : %-25s : %-25s : %s%n", "DefAuthPlugin", "AllowPubKeyRet", "User", "Passwd", "Test result");
- System.out.println("----------------------------------------------------------------------------------------------------"
- + "------------------------------");
-
- for (Class> defAuthPlugin : new Class>[] { MysqlNativePasswordPlugin.class, Sha256PasswordPlugin.class }) {
- for (String user : new String[] { "bug75670user_mnp", "bug75670user_sha" }) {
- for (String pwd : new String[] { user, "wrong*pwd", "" }) {
- for (boolean allowPubKeyRetrieval : new boolean[] { true, false }) {
- final Connection testConn;
- Statement testStmt;
-
- boolean expectedPubKeyRetrievalFail = (user.endsWith("_sha")
- || user.endsWith("_mnp") && defAuthPlugin.equals(Sha256PasswordPlugin.class)) && !allowPubKeyRetrieval
- && pwd.length() > 0;
- boolean expectedAccessDeniedFail = !user.equals(pwd);
- System.out.printf("%-25s : %-18s : %-25s : %-25s : %s%n", defAuthPlugin.getSimpleName(), allowPubKeyRetrieval, user, pwd,
- expectedPubKeyRetrievalFail ? "Fail [Pub. Key retrieval]" : expectedAccessDeniedFail ? "Fail [Access denied]" : "Ok");
-
- final Properties props = new Properties();
- props.setProperty(PropertyKey.USER.getKeyName(), user);
- props.setProperty(PropertyKey.PASSWORD.getKeyName(), pwd);
- props.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), defAuthPlugin.getName());
- props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), Boolean.toString(allowPubKeyRetrieval));
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ // change user using different credentials
+ final String swapUser = user.indexOf("_sha") == -1 ? "bug75670user_sha" : "bug75670user_mnp";
+ expectedPubKeyRetrievalFail = swapUser.endsWith("_sha") && !allowPubKeyRetrieval
+ || swapUser.endsWith("_mnp") && defAuthPlugin.equals(Sha256PasswordPlugin.class) && !allowPubKeyRetrieval;
+
+ System.out.printf("%25s : %-18s : %-25s : %-25s : %s%n", "| ChangeUser (diff)", allowPubKeyRetrieval, swapUser, swapUser,
+ expectedPubKeyRetrievalFail ? "Fail [Pub. Key retrieval]" : "Ok");
if (expectedPubKeyRetrievalFail) {
- // connection will fail due to public key retrieval failure
+ // change user will fail due to public key retrieval failure
assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, props);
- return null;
- }
- });
-
- } else if (expectedAccessDeniedFail) {
- // connection will fail due to wrong password
- assertThrows(SQLException.class, "Access denied for user '" + user + "'@.*", new Callable() {
- @SuppressWarnings("synthetic-access")
public Void call() throws Exception {
- getConnectionWithProps(sha256Url, props);
+ ((JdbcConnection) testConn).changeUser(swapUser, swapUser);
return null;
}
});
-
} else {
- // connection will succeed
- testConn = getConnectionWithProps(sha256Url, props);
- testStmt = testConn.createStatement();
- this.rs = testStmt.executeQuery("SELECT USER(), CURRENT_USER()");
- assertTrue(this.rs.next());
- assertTrue(this.rs.getString(1).startsWith(user));
- assertTrue(this.rs.getString(2).startsWith(user));
- this.rs.close();
- testStmt.close();
-
- // change user using same credentials will succeed
- System.out.printf("%25s : %-18s : %-25s : %-25s : %s%n", "| ChangeUser (same)", allowPubKeyRetrieval, user, pwd, "Ok");
- ((JdbcConnection) testConn).changeUser(user, user);
+ // change user will succeed
+ ((JdbcConnection) testConn).changeUser(swapUser, swapUser);
testStmt = testConn.createStatement();
this.rs = testStmt.executeQuery("SELECT USER(), CURRENT_USER()");
assertTrue(this.rs.next());
- assertTrue(this.rs.getString(1).startsWith(user));
- assertTrue(this.rs.getString(2).startsWith(user));
+ assertTrue(this.rs.getString(1).startsWith(swapUser));
+ assertTrue(this.rs.getString(2).startsWith(swapUser));
this.rs.close();
- testStmt.close();
-
- // change user using different credentials
- final String swapUser = user.indexOf("_sha") == -1 ? "bug75670user_sha" : "bug75670user_mnp";
- expectedPubKeyRetrievalFail = (swapUser.endsWith("_sha")
- || swapUser.endsWith("_mnp") && defAuthPlugin.equals(Sha256PasswordPlugin.class)) && !allowPubKeyRetrieval;
- System.out.printf("%25s : %-18s : %-25s : %-25s : %s%n", "| ChangeUser (diff)", allowPubKeyRetrieval, swapUser, swapUser,
- expectedPubKeyRetrievalFail ? "Fail [Pub. Key retrieval]" : "Ok");
-
- if (expectedPubKeyRetrievalFail) {
- // change user will fail due to public key retrieval failure
- assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
- public Void call() throws Exception {
- ((JdbcConnection) testConn).changeUser(swapUser, swapUser);
- return null;
- }
- });
- } else {
- // change user will succeed
- ((JdbcConnection) testConn).changeUser(swapUser, swapUser);
- testStmt = testConn.createStatement();
- this.rs = testStmt.executeQuery("SELECT USER(), CURRENT_USER()");
- assertTrue(this.rs.next());
- assertTrue(this.rs.getString(1).startsWith(swapUser));
- assertTrue(this.rs.getString(2).startsWith(swapUser));
- this.rs.close();
- }
-
- testConn.close();
}
+
+ testConn.close();
}
}
}
}
- } finally {
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
- }
+ }
+ } finally {
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
}
}
}
@@ -7579,13 +7140,17 @@ public void testBug16634180() throws Exception {
Connection c1 = null;
Connection c2 = null;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
try {
- c1 = getConnectionWithProps(new Properties());
+ c1 = getConnectionWithProps(props);
c1.setAutoCommit(false);
Statement s1 = c1.createStatement();
s1.executeUpdate("update testBug16634180 set val=val+1 where pk=0");
- c2 = getConnectionWithProps(new Properties());
+ c2 = getConnectionWithProps(props);
c2.setAutoCommit(false);
Statement s2 = c2.createStatement();
try {
@@ -7642,6 +7207,8 @@ public void testBug16634180() throws Exception {
@Test
public void testBug21934573() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.exceptionInterceptors.getKeyName(), TestBug21934573ExceptionInterceptor.class.getName());
props.setProperty(PropertyKey.replicationConnectionGroup.getKeyName(), "deadlock");
props.setProperty(PropertyKey.allowMultiQueries.getKeyName(), "true");
@@ -7773,6 +7340,13 @@ public Exception interceptException(Exception sqlEx) {
*/
@Test
public void testBug21947042() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
System.setProperty("javax.net.ssl.trustStore", "");
System.setProperty("javax.net.ssl.trustStorePassword", "");
@@ -7953,6 +7527,8 @@ public void testBug56100() throws Exception {
final String hostReplica = "replica:" + port;
final Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug56100QueryInterceptor.class.getName());
final ReplicationConnection testConn = getUnreliableReplicationConnection(new String[] { "source", "replica" }, props);
@@ -8050,157 +7626,135 @@ public void destroy() {
/**
* Tests fix for WL#8196, Support for TLSv1.2 Protocol.
*
- * This test requires community server (preferably compiled with yaSSL) in -Dcom.mysql.cj.testsuite.url and commercial server (with OpenSSL) in
- * -Dcom.mysql.cj.testsuite.url.openssl
- *
- * Test certificates from test/config/ssl-test-certs must be installed on both servers.
- *
* @throws Exception
*/
@Test
public void testTLSVersion() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
// Find out which TLS protocol versions are supported by this JVM.
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
List jvmSupportedProtocols = Arrays.asList(sslContext.createSSLEngine().getSupportedProtocols());
- final String[] testDbUrls;
Properties props = new Properties();
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
props.setProperty(PropertyKey.trustCertificateKeyStoreUrl.getKeyName(), "file:src/test/config/ssl-test-certs/ca-truststore");
props.setProperty(PropertyKey.trustCertificateKeyStoreType.getKeyName(), "JKS");
props.setProperty(PropertyKey.trustCertificateKeyStorePassword.getKeyName(), "password");
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 5, 7)) {
- testDbUrls = new String[] { BaseTestCase.dbUrl, sha256Url };
- } else {
- testDbUrls = new String[] { BaseTestCase.dbUrl };
- }
+ System.out.println(dbUrl);
+ System.out.println("JVM version: " + System.getProperty(PropertyDefinitions.SYSP_java_version));
+ System.out.println("JVM supports TLS protocols: " + jvmSupportedProtocols);
+ Connection sslConn = getConnectionWithProps(dbUrl, props);
+ assertTrue(((MysqlConnection) sslConn).getSession().isSSLEstablished());
+ System.out.println("MySQL version: " + ((MysqlConnection) sslConn).getSession().getServerSession().getServerVersion());
+ this.rs = sslConn.createStatement().executeQuery("SHOW STATUS LIKE 'ssl_version'");
+ assertTrue(this.rs.next());
+ String tlsVersionUsed = this.rs.getString(2);
+ System.out.println("TLS version used: " + tlsVersionUsed);
- for (String testDbUrl : testDbUrls) {
- System.out.println(testDbUrl);
- System.out.println("JVM version: " + System.getProperty(PropertyDefinitions.SYSP_java_version));
- System.out.println("JVM supports TLS protocols: " + jvmSupportedProtocols);
- Connection sslConn = getConnectionWithProps(testDbUrl, props);
- assertTrue(((MysqlConnection) sslConn).getSession().isSSLEstablished());
- System.out.println("MySQL version: " + ((MysqlConnection) sslConn).getSession().getServerSession().getServerVersion());
- this.rs = sslConn.createStatement().executeQuery("SHOW STATUS LIKE 'ssl_version'");
+ if (((JdbcConnection) sslConn).getSession().versionMeetsMinimum(5, 7, 10)) {
+ this.rs = sslConn.createStatement().executeQuery("SHOW GLOBAL VARIABLES LIKE 'tls_version'");
assertTrue(this.rs.next());
- String tlsVersionUsed = this.rs.getString(2);
- System.out.println("TLS version used: " + tlsVersionUsed);
-
- if (((JdbcConnection) sslConn).getSession().versionMeetsMinimum(5, 7, 10)) {
- this.rs = sslConn.createStatement().executeQuery("SHOW GLOBAL VARIABLES LIKE 'tls_version'");
- assertTrue(this.rs.next());
- List serverSupportedProtocols = Arrays.asList(this.rs.getString(2).trim().split("\\s*,\\s*"));
- String highestCommonTlsVersion = "";
- for (String p : new String[] { "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" }) {
- if (jvmSupportedProtocols.contains(p) && serverSupportedProtocols.contains(p)) {
- highestCommonTlsVersion = p;
- break;
- }
+ List serverSupportedProtocols = Arrays.asList(this.rs.getString(2).trim().split("\\s*,\\s*"));
+ String highestCommonTlsVersion = "";
+ for (String p : new String[] { "TLSv1.3", "TLSv1.2" }) {
+ if (jvmSupportedProtocols.contains(p) && serverSupportedProtocols.contains(p)) {
+ highestCommonTlsVersion = p;
+ break;
}
- System.out.println("Server supports TLS protocols: " + serverSupportedProtocols);
- System.out.println("Highest common TLS protocol: " + highestCommonTlsVersion);
-
- assertEquals(highestCommonTlsVersion, tlsVersionUsed);
- } else if (((JdbcConnection) sslConn).getSession().versionMeetsMinimum(5, 6, 46)
- && !((JdbcConnection) sslConn).getSession().versionMeetsMinimum(5, 7, 0)) {
- assertEquals("TLSv1.2", tlsVersionUsed);
- } else {
- assertEquals("TLSv1", tlsVersionUsed);
}
- System.out.println();
+ System.out.println("Server supports TLS protocols: " + serverSupportedProtocols);
+ System.out.println("Highest common TLS protocol: " + highestCommonTlsVersion);
- sslConn.close();
+ assertEquals(highestCommonTlsVersion, tlsVersionUsed);
+ } else {
+ assertEquals("TLSv1.2", tlsVersionUsed);
}
+ System.out.println();
+
+ sslConn.close();
}
/**
- * Tests fix for Bug#87379. This allows TLS version to be overridden through a new configuration option - enabledTLSProtocols. When set to some combination
- * of TLSv1, TLSv1.1, or TLSv1.2 (comma-separated, no spaces), the default behavior restricting the TLS version based on JRE and MySQL Server version is
+ * Tests fix for Bug#87379. This allows TLS version to be overridden through a new configuration option - tlsVersions. When set to some combination
+ * of TLSv1.2 or TLSv1.3 (comma-separated, no spaces), the default behavior restricting the TLS version based on JRE and MySQL Server version is
* bypassed to enable or restrict specific TLS versions.
*
- * This test requires community server (preferably compiled with yaSSL) in -Dcom.mysql.cj.testsuite.url and commercial server (with OpenSSL) in
- * -Dcom.mysql.cj.testsuite.url.openssl
- *
- * Test certificates from testsuite/ssl-test-certs must be installed on both servers.
- *
* @throws Exception
*/
@Test
public void testEnableTLSVersion() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
// Find out which TLS protocol versions are supported by this JVM.
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
List jvmSupportedProtocols = Arrays.asList(sslContext.createSSLEngine().getSupportedProtocols());
- final String[] testDbUrls;
Properties props = new Properties();
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.requireSSL.getKeyName(), "true");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
props.setProperty(PropertyKey.trustCertificateKeyStoreUrl.getKeyName(), "file:src/test/config/ssl-test-certs/ca-truststore");
props.setProperty(PropertyKey.trustCertificateKeyStoreType.getKeyName(), "JKS");
props.setProperty(PropertyKey.trustCertificateKeyStorePassword.getKeyName(), "password");
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 5, 7)) {
- testDbUrls = new String[] { BaseTestCase.dbUrl, sha256Url };
+ System.out.println(dbUrl);
+ System.out.println("JVM version: " + System.getProperty(PropertyDefinitions.SYSP_java_version));
+ System.out.println("JVM supports TLS protocols: " + jvmSupportedProtocols);
+ Connection sslConn = getConnectionWithProps(dbUrl, props);
+ assertTrue(((MysqlConnection) sslConn).getSession().isSSLEstablished());
+ System.out.println("MySQL version: " + ((MysqlConnection) sslConn).getSession().getServerSession().getServerVersion());
+ List commonSupportedProtocols = new ArrayList<>();
+ if (((JdbcConnection) sslConn).getSession().versionMeetsMinimum(5, 7, 10)) {
+ this.rs = sslConn.createStatement().executeQuery("SHOW GLOBAL VARIABLES LIKE 'tls_version'");
+ assertTrue(this.rs.next());
+ List serverSupportedProtocols = Arrays.asList(this.rs.getString(2).trim().split("\\s*,\\s*"));
+ System.out.println("Server supports TLS protocols: " + serverSupportedProtocols);
+ commonSupportedProtocols.addAll(serverSupportedProtocols);
+ commonSupportedProtocols.retainAll(jvmSupportedProtocols);
} else {
- testDbUrls = new String[] { BaseTestCase.dbUrl };
- }
-
- for (String testDbUrl : testDbUrls) {
- System.out.println(testDbUrl);
- System.out.println("JVM version: " + System.getProperty(PropertyDefinitions.SYSP_java_version));
- System.out.println("JVM supports TLS protocols: " + jvmSupportedProtocols);
- Connection sslConn = getConnectionWithProps(testDbUrl, props);
- assertTrue(((MysqlConnection) sslConn).getSession().isSSLEstablished());
- System.out.println("MySQL version: " + ((MysqlConnection) sslConn).getSession().getServerSession().getServerVersion());
- List commonSupportedProtocols = new ArrayList<>();
- if (((JdbcConnection) sslConn).getSession().versionMeetsMinimum(5, 7, 10)) {
- this.rs = sslConn.createStatement().executeQuery("SHOW GLOBAL VARIABLES LIKE 'tls_version'");
- assertTrue(this.rs.next());
- List serverSupportedProtocols = Arrays.asList(this.rs.getString(2).trim().split("\\s*,\\s*"));
- System.out.println("Server supports TLS protocols: " + serverSupportedProtocols);
- commonSupportedProtocols.addAll(serverSupportedProtocols);
- commonSupportedProtocols.retainAll(jvmSupportedProtocols);
- } else if (((JdbcConnection) sslConn).getSession().versionMeetsMinimum(5, 6, 46)) {
- commonSupportedProtocols.add("TLSv1");
- commonSupportedProtocols.add("TLSv1.1");
- commonSupportedProtocols.add("TLSv1.2");
- } else {
- commonSupportedProtocols.add("TLSv1");
- }
+ commonSupportedProtocols.add("TLSv1.2");
+ commonSupportedProtocols.add("TLSv1.3");
+ commonSupportedProtocols.retainAll(jvmSupportedProtocols);
+ }
- String[] testingProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1" };
- for (String protocol : testingProtocols) {
- Properties testProps = new Properties();
- testProps.putAll(props);
- testProps.setProperty(PropertyKey.enabledTLSProtocols.getKeyName(), protocol);
- System.out.println("Testing " + protocol + " expecting connection: " + commonSupportedProtocols.contains(protocol));
- try {
- Connection tlsConn = getConnectionWithProps(testDbUrl, testProps);
- if (!commonSupportedProtocols.contains(protocol)) {
- fail("Expected to fail connection with " + protocol + " due to lack of jvm/server support.");
- }
- ResultSet rset = tlsConn.createStatement().executeQuery("SHOW STATUS LIKE 'ssl_version'");
- assertTrue(rset.next());
- String tlsVersion = rset.getString(2);
- assertEquals(protocol, tlsVersion);
- tlsConn.close();
- } catch (Exception e) {
- if (commonSupportedProtocols.contains(protocol)) {
- e.printStackTrace();
- fail("Expected to be able to connect with " + protocol + " protocol, but failed.");
- }
+ String[] testingProtocols = { "TLSv1.2", "TLSv1.3" };
+ for (String protocol : testingProtocols) {
+ Properties testProps = new Properties();
+ testProps.putAll(props);
+ testProps.setProperty(PropertyKey.tlsVersions.getKeyName(), protocol);
+ System.out.println("Testing " + protocol + " expecting connection: " + commonSupportedProtocols.contains(protocol));
+ try {
+ Connection tlsConn = getConnectionWithProps(dbUrl, testProps);
+ assertTrue(commonSupportedProtocols.contains(protocol), "Expected to fail connection with " + protocol + " due to lack of jvm/server support.");
+ ResultSet rset = tlsConn.createStatement().executeQuery("SHOW STATUS LIKE 'ssl_version'");
+ assertTrue(rset.next());
+ String tlsVersion = rset.getString(2);
+ assertEquals(protocol, tlsVersion);
+ tlsConn.close();
+ } catch (Exception e) {
+ if (commonSupportedProtocols.contains(protocol)) {
+ e.printStackTrace();
+ fail("Expected to be able to connect with " + protocol + " protocol, but failed.");
}
}
- System.out.println();
- sslConn.close();
}
+ System.out.println();
+ sslConn.close();
+
}
/**
@@ -8210,8 +7764,11 @@ public void testEnableTLSVersion() throws Exception {
*/
@Test
public void testBug56122() throws Exception {
- for (final Connection testConn : new Connection[] { this.conn, getFailoverConnection(), getLoadBalancedConnection(),
- getSourceReplicaReplicationConnection() }) {
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ for (final Connection testConn : new Connection[] { this.conn, getFailoverConnection(props), getLoadBalancedConnection(props),
+ getSourceReplicaReplicationConnection(props) }) {
testConn.createClob();
testConn.createBlob();
testConn.createNClob();
@@ -8253,6 +7810,8 @@ public void testBug21286268() throws Exception {
final String[] hosts = new String[] { SOURCE, REPLICA };
final Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.connectTimeout.getKeyName(), "100");
props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "2"); // Failed connection attempts will show up twice.
final Set downedHosts = new HashSet<>();
@@ -8578,7 +8137,9 @@ public void testBug77171() throws Exception {
}
Properties props = new Properties();
- props.put("sessionVariables", "sql_mode='" + newSqlMode + "'");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.sessionVariables.getKeyName(), "sql_mode='" + newSqlMode + "'");
Connection testConn = getConnectionWithProps(props);
assertFalse(((JdbcConnection) testConn).getSession().getServerSession().useAnsiQuotedIdentifiers());
assertFalse(((JdbcConnection) testConn).getSession().getServerSession().isNoBackslashEscapesSet());
@@ -8586,7 +8147,9 @@ public void testBug77171() throws Exception {
props.clear();
newSqlMode = sqlMode + "ANSI_QUOTES";
- props.put("sessionVariables", "sql_mode='" + newSqlMode + "'");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.sessionVariables.getKeyName(), "sql_mode='" + newSqlMode + "'");
testConn = getConnectionWithProps(props);
assertTrue(((JdbcConnection) testConn).getSession().getServerSession().useAnsiQuotedIdentifiers());
assertFalse(((JdbcConnection) testConn).getSession().getServerSession().isNoBackslashEscapesSet());
@@ -8594,7 +8157,9 @@ public void testBug77171() throws Exception {
props.clear();
newSqlMode = sqlMode + "NO_BACKSLASH_ESCAPES";
- props.put("sessionVariables", "sql_mode='" + newSqlMode + "'");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.sessionVariables.getKeyName(), "sql_mode='" + newSqlMode + "'");
testConn = getConnectionWithProps(props);
assertFalse(((JdbcConnection) testConn).getSession().getServerSession().useAnsiQuotedIdentifiers());
assertTrue(((JdbcConnection) testConn).getSession().getServerSession().isNoBackslashEscapesSet());
@@ -8602,7 +8167,9 @@ public void testBug77171() throws Exception {
props.clear();
newSqlMode = sqlMode + "ANSI_QUOTES,NO_BACKSLASH_ESCAPES";
- props.put("sessionVariables", "sql_mode='" + newSqlMode + "'");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.sessionVariables.getKeyName(), "sql_mode='" + newSqlMode + "'");
testConn = getConnectionWithProps(props);
assertTrue(((JdbcConnection) testConn).getSession().getServerSession().useAnsiQuotedIdentifiers());
assertTrue(((JdbcConnection) testConn).getSession().getServerSession().isNoBackslashEscapesSet());
@@ -8623,6 +8190,8 @@ public void testBug22730682() throws Exception {
final String dummyHost = "bug22730682:12345";
final Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
Connection testConn;
final String lbConnGroup1 = "Bug22730682LB1";
@@ -8700,6 +8269,8 @@ private void subTestBug22848249A() throws Exception {
System.out.println("********************************************************************************");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "0");
props.setProperty(PropertyKey.loadBalanceConnectionGroup.getKeyName(), lbConnGroup);
Connection testConn = getUnreliableLoadBalancedConnection(new String[] { host1, host2, host3 }, props);
@@ -8764,9 +8335,8 @@ private void subTestBug22848249A() throws Exception {
connectedHost = newConnectedHost;
connectionSwaps++;
}
- if (--attemptsLeft == 0) {
- fail("Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
- }
+ assertFalse(--attemptsLeft == 0,
+ "Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
}
System.out.println("\t2. Swapped connections " + connectionSwaps + " times before hitting the new host.");
assertTrue(connectionSwaps > 0); // Non-deterministic, but something must be wrong if there are no swaps after 100 transaction boundaries.
@@ -8796,9 +8366,8 @@ private void subTestBug22848249A() throws Exception {
connectedHost = newConnectedHost;
connectionSwaps++;
}
- if (--attemptsLeft == 0) {
- fail("Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
- }
+ assertFalse(--attemptsLeft == 0,
+ "Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
}
System.out.println("\t3. Swapped connections " + connectionSwaps + " times before hitting the new host.");
assertTrue(connectionSwaps > 0); // Non-deterministic, but something must be wrong if there are no swaps after 100 transaction boundaries.
@@ -8865,6 +8434,8 @@ private void subTestBug22848249B() throws Exception {
System.out.println("********************************************************************************");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "0");
props.setProperty(PropertyKey.loadBalanceConnectionGroup.getKeyName(), lbConnGroup);
Connection testConn = getUnreliableLoadBalancedConnection(new String[] { host1, host2, host3 }, props);
@@ -8931,9 +8502,8 @@ private void subTestBug22848249B() throws Exception {
connectedHost = newConnectedHost;
connectionSwaps++;
}
- if (--attemptsLeft == 0) {
- fail("Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
- }
+ assertFalse(--attemptsLeft == 0,
+ "Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
}
System.out.println("\t2. Swapped connections " + connectionSwaps + " times before hitting the new host.");
assertTrue(connectionSwaps > 0); // Non-deterministic, but something must be wrong if there are no swaps after 100 transaction boundaries.
@@ -8963,9 +8533,8 @@ private void subTestBug22848249B() throws Exception {
connectedHost = newConnectedHost;
connectionSwaps++;
}
- if (--attemptsLeft == 0) {
- fail("Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
- }
+ assertFalse(--attemptsLeft == 0,
+ "Failed to swap to the newly added host after 100 transaction boundaries and " + connectionSwaps + " connection swaps.");
}
System.out.println("\t3. Swapped connections " + connectionSwaps + " times before hitting the new host.");
assertTrue(connectionSwaps > 0); // Non-deterministic, but something must be wrong if there are no swaps after 100 transaction boundaries.
@@ -9035,6 +8604,8 @@ private void subTestBug22848249C() throws Exception {
* Initial connection will be able to use all hosts, even after removed from the connection group.
*/
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "0");
props.setProperty(PropertyKey.loadBalanceConnectionGroup.getKeyName(), lbConnGroup);
Connection testConn = getUnreliableLoadBalancedConnection(new String[] { host1, host2, host3, host4 }, props);
@@ -9147,6 +8718,8 @@ private void subTestBug22848249D() throws Exception {
* Initial connection will be able to use only the hosts available when it was initialized, even after adding new ones to the connection group.
*/
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "0");
props.setProperty(PropertyKey.loadBalanceConnectionGroup.getKeyName(), lbConnGroup);
Connection testConn = getUnreliableLoadBalancedConnection(new String[] { host1, host2 }, props);
@@ -9259,7 +8832,7 @@ public void testBug22678872() throws Exception {
props.put(PropertyKey.USER.getKeyName(), username);
props.put(PropertyKey.PASSWORD.getKeyName(), password);
props.put(PropertyKey.DBNAME.getKeyName(), database);
- props.put(PropertyKey.useSSL.getKeyName(), "false");
+ props.put(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.put(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "0"); // Speed up the test execution.
// Replicate the properties used in FabricMySQLConnectionProxy.getActiveConnection().
props.put(PropertyKey.retriesAllDown.getKeyName(), "1");
@@ -9596,6 +9169,8 @@ public void testBug77649() throws Exception {
}
Properties props = getHostFreePropertiesFromTestsuiteUrl();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.socketFactory.getKeyName(), UnreliableSocketFactory.class.getName());
for (String h : hosts) {
getConnectionWithProps(String.format("jdbc:mysql://%s:%s", h, port), props).close();
@@ -9612,17 +9187,13 @@ public void testBug77649() throws Exception {
*/
@Test
public void testBug74711() throws Exception {
- if (!((MysqlConnection) this.conn).getSession().getServerSession().isQueryCacheEnabled()) {
- System.err.println("Warning! testBug77411() requires a server supporting a query cache.");
- return;
- }
+ assumeTrue(((MysqlConnection) this.conn).getSession().getServerSession().isQueryCacheEnabled(),
+ "testBug77411() requires a server supporting a query cache.");
+
this.rs = this.stmt.executeQuery("SELECT @@global.query_cache_type, @@global.query_cache_size");
this.rs.next();
- if (!"ON".equalsIgnoreCase(this.rs.getString(1)) || "0".equals(this.rs.getString(2))) {
- System.err
- .println("Warning! testBug77411() requires a server started with the options '--query_cache_type=1' and '--query_cache_size=N', (N > 0).");
- return;
- }
+ assumeTrue("ON".equalsIgnoreCase(this.rs.getString(1)) && !"0".equals(this.rs.getString(2)),
+ "testBug77411() requires a server started with the options '--query_cache_type=1' and '--query_cache_size=N', (N > 0).");
boolean useLocTransSt = false;
boolean useElideSetAC = false;
@@ -9653,6 +9224,8 @@ public void testBug75209() throws Exception {
boolean useLocTransSt = false;
final Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
do {
this.stmt.executeUpdate("TRUNCATE TABLE testBug75209");
this.stmt.executeUpdate("INSERT INTO testBug75209 VALUES (1)");
@@ -9698,7 +9271,10 @@ public void testBug75209() throws Exception {
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("");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ final Connection testConn1 = getConnectionWithProps(props);
testConn1.setNetworkTimeout(Executors.newSingleThreadExecutor(), 1000);
testConn1.close();
@@ -9706,7 +9282,7 @@ public void testBug75615() throws Exception {
// 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("");
+ final Connection testConn2 = getConnectionWithProps(props);
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.
@@ -9726,7 +9302,7 @@ public void execute(Runnable command) {
// Test the expected exception on null executor.
assertThrows(SQLException.class, "Executor can not be null", new Callable() {
public Void call() throws Exception {
- Connection testConn = getConnectionWithProps("");
+ Connection testConn = getConnectionWithProps(props);
testConn.setNetworkTimeout(null, 1000);
testConn.close();
return null;
@@ -9741,15 +9317,14 @@ public Void call() throws Exception {
*/
@Test
public void testBug70785() throws Exception {
+ assumeTrue(versionMeetsMinimum(5, 5), "MySQL 5.5+ is required to run this test.");
+
// 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);
@@ -9772,6 +9347,8 @@ public void testBug70785() throws Exception {
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(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.cacheServerConfiguration.getKeyName(), Boolean.toString(cacheServerConf));
props.setProperty(PropertyKey.useLocalTransactionState.getKeyName(), Boolean.toString(useLocTransSt));
props.setProperty(PropertyKey.elideSetAutoCommits.getKeyName(), Boolean.toString(elideSetAutoCommit));
@@ -9804,319 +9381,185 @@ public void testBug70785() throws Exception {
}
/**
- * This test requires two server instances:
- * 1) main test server pointed to by the com.mysql.cj.testsuite.url variable configured without RSA encryption support (sha256_password_private_key_path,
- * sha256_password_public_key_path, caching_sha2_password_private_key_path and caching_sha2_password_public_key_path config options are unset).
- * 2) additional server instance pointed to by the com.mysql.cj.testsuite.url.openssl variable configured with
- * default-authentication-plugin=sha256_password, RSA encryption enabled, and server configuration options "caching_sha2_password_private_key_path" and
- * "caching_sha2_password_public_key_path" set to the same values as "sha256_password_private_key_path" and "sha256_password_public_key_path" respectively.
- *
- * To run this test, please add this variable to the ant call:
- * -Dcom.mysql.cj.testsuite.url.openssl=jdbc:mysql://localhost:3307/test?user=root&password=pwd
+ * Test for caching_sha2_password authentication.
*
* @throws Exception
*/
@Test
public void testCachingSha2PasswordPlugin() throws Exception {
+
+ assumeTrue(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 3), "Requires MySQL 8.0.3+.");
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+ assumeTrue(pluginIsActive(this.stmt, "caching_sha2_password"), "caching_sha2_password plugin required to run this test");
+
String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
System.setProperty("javax.net.ssl.keyStore", trustStorePath);
System.setProperty("javax.net.ssl.keyStorePassword", "password");
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "password");
- /*
- * test against server without RSA support
- */
- if (versionMeetsMinimum(8, 0, 3)) {
- if (!pluginIsActive(this.stmt, "caching_sha2_password")) {
- fail("caching_sha2_password required to run this test");
- }
-
- // newer GPL servers, like 8.0.4+, are using OpenSSL and can use RSA encryption, while old ones compiled with yaSSL cannot
- boolean gplWithRSA = allowsRsa(this.stmt);
-
- try {
- if (!versionMeetsMinimum(8, 0, 5)) {
- this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
- }
- createUser("'wl11060user'@'%'", "identified WITH caching_sha2_password");
- this.stmt.executeUpdate("grant all on *.* to 'wl11060user'@'%'");
- createUser("'wl11060nopassword'@'%'", "identified WITH caching_sha2_password");
- this.stmt.executeUpdate("grant all on *.* to 'wl11060nopassword'@'%'");
- if (!versionMeetsMinimum(8, 0, 5)) {
- this.stmt.executeUpdate("SET GLOBAL old_passwords= 2");
- this.stmt.executeUpdate("SET SESSION old_passwords= 2");
- }
- this.stmt.executeUpdate(versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl11060user'@'%' IDENTIFIED BY 'pwd'"
- : "set password for 'wl11060user'@'%' = PASSWORD('pwd')");
- this.stmt.executeUpdate("flush privileges");
-
- final Properties propsNoRetrieval = new Properties();
- propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
- propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- final Properties propsNoRetrievalNoPassword = new Properties();
- propsNoRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl11060nopassword");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- final Properties propsAllowRetrieval = new Properties();
- propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
- propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- final Properties propsAllowRetrievalNoPassword = new Properties();
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl11060nopassword");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- // 1. without SSL
- // SQLException expected due to server doesn't recognize Public Key Retrieval packet
- assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
- public Void call() throws Exception {
- getConnectionWithProps(propsNoRetrieval);
- return null;
- }
- });
- if (gplWithRSA) {
- assertCurrentUser(null, propsAllowRetrieval, "wl11060user", false);
- } else {
- assertThrows(SQLException.class, "Access denied for user 'wl11060user'.*", new Callable() {
- public Void call() throws Exception {
- getConnectionWithProps(propsAllowRetrieval);
- return null;
- }
- });
- }
-
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl11060nopassword", false);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
-
- // 2. with serverRSAPublicKeyFile specified
- // SQLException expected due to server not recognizing RSA encrypted payload
- propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ boolean withCachingTestRsaKeys = supportsTestCachingSha2PasswordKeys(this.stmt);
- this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ try {
+ // create user with long password and caching_sha2_password auth
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
+ }
+ createUser(this.stmt, "'wl11060user'@'%'", "identified WITH caching_sha2_password");
+ this.stmt.executeUpdate("grant all on *.* to 'wl11060user'@'%'");
+ createUser(this.stmt, "'wl11060nopassword'@'%'", "identified WITH caching_sha2_password");
+ this.stmt.executeUpdate("grant all on *.* to 'wl11060nopassword'@'%'");
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords= 2");
+ this.stmt.executeUpdate("SET SESSION old_passwords= 2");
+ }
+ this.stmt.executeUpdate(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl11060user'@'%' IDENTIFIED BY 'pwd'"
+ : "set password for 'wl11060user'@'%' = PASSWORD('pwd')");
+ this.stmt.executeUpdate("flush privileges");
- assertThrows(SQLException.class, "Access denied for user 'wl11060user'.*", new Callable() {
- public Void call() throws Exception {
- getConnectionWithProps(propsNoRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Access denied for user 'wl11060user'.*", new Callable() {
- public Void call() throws Exception {
- getConnectionWithProps(propsAllowRetrieval);
- return null;
- }
- });
+ final Properties propsNoRetrieval = new Properties();
+ propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
+ propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl11060nopassword", false);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
+ final Properties propsNoRetrievalNoPassword = new Properties();
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl11060nopassword");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- // 3. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
+ final Properties propsAllowRetrieval = new Properties();
+ propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
+ propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
+ propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(null, propsNoRetrieval, "wl11060user", true);
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl11060nopassword", false);
+ final Properties propsAllowRetrievalNoPassword = new Properties();
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl11060nopassword");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(null, propsAllowRetrieval, "wl11060user", true);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
+ // 1. with client-default MysqlNativePasswordPlugin
+ propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
+ propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
- // over SSL with client-default CachingSha2PasswordPlugin
- propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
- propsNoRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
- propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
+ // 1.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
- this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(null, propsNoRetrieval, "wl11060user", true);
- assertCurrentUser(null, propsNoRetrievalNoPassword, "wl11060nopassword", false);
+ assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
+ return null;
+ }
+ });
- this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(null, propsAllowRetrieval, "wl11060user", true);
- assertCurrentUser(null, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl11060nopassword", false);
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl11060user", false);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
- // 4. without SSL but now we hit the cached scramble
- propsNoRetrieval.clear();
- propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
- propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ // 1.2. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
- propsAllowRetrieval.clear();
- propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
- propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl11060user", true);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl11060nopassword", false);
- assertCurrentUser(null, propsNoRetrieval, "wl11060user", false); // note that is was failing on step 1
- assertCurrentUser(null, propsAllowRetrieval, "wl11060user", false); // note that is was failing on step 1
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl11060user", true);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
- } finally {
- this.stmt.executeUpdate("flush privileges");
- if (!versionMeetsMinimum(8, 0, 5)) {
- this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
- }
- }
- }
+ // 2. with client-default CachingSha2PasswordPlugin
+ propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
+ propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
- /*
- * test against server with RSA support
- */
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 3)) {
+ // 2.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
- if (!pluginIsActive(this.sha256Stmt, "caching_sha2_password")) {
- fail("caching_sha2_password required to run this test");
- }
- if (!allowsRsa(this.sha256Stmt)) {
- fail("RSA encryption must be enabled on " + sha256Url + " to run this test");
- }
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl11060user", false); // wl11060user scramble is cached now, thus authenticated successfully
- try {
- // create user with long password and caching_sha2_password auth
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
- }
- createUser(this.sha256Stmt, "'wl11060user'@'%'", "identified WITH caching_sha2_password");
- this.sha256Stmt.executeUpdate("grant all on *.* to 'wl11060user'@'%'");
- createUser(this.sha256Stmt, "'wl11060nopassword'@'%'", "identified WITH caching_sha2_password");
- this.sha256Stmt.executeUpdate("grant all on *.* to 'wl11060nopassword'@'%'");
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords= 2");
- this.sha256Stmt.executeUpdate("SET SESSION old_passwords= 2");
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrieval); // now, with full authentication, it's failed
+ return null;
}
- this.sha256Stmt.executeUpdate(
- ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl11060user'@'%' IDENTIFIED BY 'pwd'"
- : "set password for 'wl11060user'@'%' = PASSWORD('pwd')");
- this.sha256Stmt.executeUpdate("flush privileges");
-
- final Properties propsNoRetrieval = new Properties();
- propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
- propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
-
- final Properties propsNoRetrievalNoPassword = new Properties();
- propsNoRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl11060nopassword");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
-
- final Properties propsAllowRetrieval = new Properties();
- propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl11060user");
- propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
- propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
-
- final Properties propsAllowRetrievalNoPassword = new Properties();
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl11060nopassword");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
-
- // 1. with client-default MysqlNativePasswordPlugin
- propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
- propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
-
- // 1.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
+ });
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl11060nopassword", false);
+
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl11060user", false);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
+
+ // 2.2. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl11060user", true);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl11060nopassword", false);
+
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl11060user", false);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
+
+ // 3. with serverRSAPublicKeyFile specified
+ propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
+
+ // 3.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+
+ if (withCachingTestRsaKeys) {
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl11060user", false);
+ } else {
+ assertThrows(SQLException.class, "Access denied for user 'wl11060user'.*", new Callable() {
@SuppressWarnings("synthetic-access")
public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrieval);
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
return null;
}
});
+ }
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl11060nopassword", false);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl11060nopassword", false);
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl11060user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
-
- // 1.2. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl11060user", true);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl11060nopassword", false);
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl11060user", true);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
-
- // 2. with client-default CachingSha2PasswordPlugin
- propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
- propsNoRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
- propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), CachingSha2PasswordPlugin.class.getName());
-
- // 2.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl11060user", false); // wl11060user scramble is cached now, thus authenticated successfully
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertThrows(SQLException.class, "Public Key Retrieval is not allowed", new Callable() {
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ if (withCachingTestRsaKeys) {
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl11060user", false);
+ } else {
+ assertThrows(SQLException.class, "Access denied for user 'wl11060user'.*", new Callable() {
@SuppressWarnings("synthetic-access")
public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrieval); // now, with full authentication, it's failed
+ getConnectionWithProps(dbUrl, propsAllowRetrieval);
return null;
}
});
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl11060nopassword", false);
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl11060user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
-
- // 2.2. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl11060user", true);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl11060nopassword", false);
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl11060user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
-
- // 3. with serverRSAPublicKeyFile specified
- propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
-
- // 3.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl11060user", false);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl11060nopassword", false);
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl11060user", false);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
-
- // 3.2. Runtime setServerRSAPublicKeyFile must be denied
- final Connection c2 = getConnectionWithProps(sha256Url, propsNoRetrieval);
+ }
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
+
+ // 3.2. Runtime setServerRSAPublicKeyFile must be denied
+ if (withCachingTestRsaKeys) {
+ final Connection c2 = getConnectionWithProps(dbUrl, propsNoRetrieval);
assertThrows(PropertyNotModifiableException.class, "Dynamic change of ''serverRSAPublicKeyFile'' is not allowed.", new Callable() {
public Void call() throws Exception {
((JdbcConnection) c2).getPropertySet().getProperty(PropertyKey.serverRSAPublicKeyFile)
@@ -10125,189 +9568,187 @@ public Void call() throws Exception {
}
});
c2.close();
-
- // 3.3. Runtime setAllowPublicKeyRetrieval must be denied
- final Connection c3 = getConnectionWithProps(sha256Url, propsNoRetrieval);
- assertThrows(PropertyNotModifiableException.class, "Dynamic change of ''allowPublicKeyRetrieval'' is not allowed.", new Callable() {
- public Void call() throws Exception {
- ((JdbcConnection) c3).getPropertySet().getProperty(PropertyKey.allowPublicKeyRetrieval).setValue(true);
- return null;
- }
- });
- c3.close();
-
- // 3.4. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsNoRetrieval, "wl11060user", true);
- assertCurrentUser(sha256Url, propsNoRetrievalNoPassword, "wl11060nopassword", false);
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
- assertCurrentUser(sha256Url, propsAllowRetrieval, "wl11060user", true);
- assertCurrentUser(sha256Url, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
-
- // 4. with wrong serverRSAPublicKeyFile specified
- propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
- propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
-
- // 4.1. RSA
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "false");
-
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
-
- this.sha256Stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
-
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ } else {
+ assertThrows(SQLException.class, "Access denied for user 'wl11060user'.*", new Callable() {
@SuppressWarnings("synthetic-access")
public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword);
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
return null;
}
});
+ }
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword);
- return null;
- }
- });
+ // 3.4. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
- // 4.2. over SSL
- propsNoRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.useSSL.getKeyName(), "true");
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertCurrentUser(dbUrl, propsNoRetrieval, "wl11060user", true);
+ assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl11060nopassword", false);
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+ assertCurrentUser(dbUrl, propsAllowRetrieval, "wl11060user", true);
+ assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl11060nopassword", false);
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword);
- return null;
- }
- });
+ // 4. with wrong serverRSAPublicKeyFile specified
+ propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
+ propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
- propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsNoRetrievalNoPassword);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrieval);
- return null;
- }
- });
- assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
- @SuppressWarnings("synthetic-access")
- public Void call() throws Exception {
- getConnectionWithProps(sha256Url, propsAllowRetrievalNoPassword);
- return null;
- }
- });
+ // 4.1. RSA
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
- } finally {
- if (!((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(8, 0, 5)) {
- this.sha256Stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+
+ this.stmt.executeUpdate("flush privileges"); // to ensure that we'll go through the full authentication
+
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword);
+ return null;
+ }
+ });
+
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword);
+ return null;
+ }
+ });
+
+ // 4.2. over SSL
+ propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
+
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
+
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword);
+ return null;
+ }
+ });
+
+ propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrieval);
+ return null;
+ }
+ });
+ assertThrows(SQLException.class, "Unable to read public key ", new Callable() {
+ @SuppressWarnings("synthetic-access")
+ public Void call() throws Exception {
+ getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword);
+ return null;
}
+ });
+
+ } finally {
+ if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
+ this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
}
}
}
@@ -10322,9 +9763,15 @@ public Void call() throws Exception {
*/
@Test
public void testBug88242() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
Properties props = new Properties();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "true");
- props.setProperty(PropertyKey.verifyServerCertificate.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.socketTimeout.getKeyName(), "1500");
@@ -10372,7 +9819,7 @@ public void testBug88232() throws Exception {
createTable("testBug88232", "(id INT)", "INNODB");
Properties props = new Properties();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.autoReconnect.getKeyName(), "true");
props.setProperty(PropertyKey.socketTimeout.getKeyName(), "2000");
@@ -10424,33 +9871,18 @@ public Void call() throws Exception {
@Test
public void testBug27131768() throws Exception {
Properties props = new Properties();
- props.setProperty("useServerPrepStmts", "true");
- props.setProperty("useInformationSchema", "true");
- props.setProperty("useCursorFetch", "true");
- props.setProperty("defaultFetchSize", "3");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "true");
+ props.setProperty(PropertyKey.useInformationSchema.getKeyName(), "true");
+ props.setProperty(PropertyKey.useCursorFetch.getKeyName(), "true");
+ props.setProperty(PropertyKey.defaultFetchSize.getKeyName(), "3");
Connection testConn = getConnectionWithProps(props);
testConn.createStatement().executeQuery("SELECT 1");
testConn.close();
}
- /**
- * Tests fix for Bug#79612 (22362474), CONNECTION ATTRIBUTES LOST WHEN CONNECTING WITHOUT DEFAULT DATABASE.
- *
- * @throws Exception
- */
- @Test
- public void testBug79612() throws Exception {
- // The case with database present in URL is covered by testConnectionAttributes() test case.
- // Testing without database here.
- if (versionMeetsMinimum(5, 6)) {
- testConnectionAttributes(getNoDbUrl(dbUrl));
- }
- if (this.sha256Conn != null && ((JdbcConnection) this.sha256Conn).getSession().versionMeetsMinimum(5, 6, 5)) {
- testConnectionAttributes(getNoDbUrl(sha256Url));
- }
- }
-
/**
* Tests fix for Bug#88227 (27029657), Connector/J 5.1.44 cannot be used against MySQL 5.7.20 without warnings.
*
@@ -10458,25 +9890,41 @@ public void testBug79612() throws Exception {
*/
@Test
public void testBug88227() throws Exception {
- java.sql.Connection testConn = getConnectionWithProps("statementInterceptors=" + Bug88227QueryInterceptor.class.getName());
- Bug88227QueryInterceptor.mayHaveWarnings = false;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug88227QueryInterceptor.class.getName());
+ Bug88227QueryInterceptor.enabled = false; // some warnings are expected here when running against old server versions
+ java.sql.Connection testConn = getConnectionWithProps(props);
+ Bug88227QueryInterceptor.enabled = true;
testConn.getTransactionIsolation();
testConn.isReadOnly();
testConn.close();
}
public static class Bug88227QueryInterceptor extends BaseQueryInterceptor {
- public static boolean mayHaveWarnings = true;
+ public static boolean enabled = false;
@Override
public T preProcess(Supplier sql, Query interceptedQuery) {
- assertFalse(sql.get().contains("SHOW WARNINGS"), "Unexpected [SHOW WARNINGS] was issued");
+ if (enabled) {
+ assertFalse(sql.get().contains("SHOW WARNINGS"), "Unexpected [SHOW WARNINGS] was issued");
+ }
return super.preProcess(sql, interceptedQuery);
}
+ @Override
+ public M preProcess(M queryPacket) {
+ if (enabled) {
+ String sql = StringUtils.toString(queryPacket.getByteBuffer(), 1, (queryPacket.getPosition() - 1));
+ assertFalse(sql.contains("SHOW WARNINGS"), "Unexpected [SHOW WARNINGS] was issued");
+ }
+ return super.preProcess(queryPacket);
+ }
+
@Override
public T postProcess(Supplier sql, Query interceptedQuery, T originalResultSet, ServerSession serverSession) {
- if (!mayHaveWarnings) {
+ if (enabled) {
assertEquals(0, ((NativeSession) interceptedQuery.getSession()).getProtocol().getWarningCount(), "Warnings while executing [" + sql + "]");
}
return super.postProcess(sql, interceptedQuery, originalResultSet, serverSession);
@@ -10493,12 +9941,22 @@ public void testBug26819691() throws Exception {
assertThrows(SQLException.class, "The connection property 'packetDebugBufferSize' only accepts integer values in the range of 1 - 2147483647, "
+ "the value '0' exceeds this range\\.", new Callable() {
public Void call() throws Exception {
- getConnectionWithProps("packetDebugBufferSize=0,enablePacketDebug=true");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.packetDebugBufferSize.getKeyName(), "0");
+ props.setProperty(PropertyKey.enablePacketDebug.getKeyName(), "true");
+ getConnectionWithProps(props);
return null;
}
});
- getConnectionWithProps("packetDebugBufferSize=1,enablePacketDebug=true").close();
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.packetDebugBufferSize.getKeyName(), "1");
+ props.setProperty(PropertyKey.enablePacketDebug.getKeyName(), "true");
+ getConnectionWithProps(props).close();
}
/**
@@ -10514,8 +9972,11 @@ public void testBug86741() throws Exception {
this.stmt.execute("SET GLOBAL autocommit=0");
try {
Connection testConn;
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
- testConn = getConnectionWithProps("");
+ testConn = getConnectionWithProps(props);
assertTrue(testConn.getAutoCommit(), "Wrong connection autocommit state");
this.rs = testConn.createStatement().executeQuery("SELECT @@global.autocommit, @@session.autocommit");
this.rs.next();
@@ -10523,7 +9984,7 @@ public void testBug86741() throws Exception {
assertEquals(1, this.rs.getInt(2), "Wrong @@session.autocommit");
testConn.close();
- testConn = getFailoverConnection();
+ testConn = getFailoverConnection(props);
assertTrue(testConn.getAutoCommit(), "Wrong connection autocommit state");
this.rs = testConn.createStatement().executeQuery("SELECT @@global.autocommit, @@session.autocommit");
this.rs.next();
@@ -10531,7 +9992,7 @@ public void testBug86741() throws Exception {
assertEquals(1, this.rs.getInt(2), "Wrong @@session.autocommit");
testConn.close();
- testConn = getLoadBalancedConnection();
+ testConn = getLoadBalancedConnection(props);
assertTrue(testConn.getAutoCommit(), "Wrong connection autocommit state");
this.rs = testConn.createStatement().executeQuery("SELECT @@global.autocommit, @@session.autocommit");
this.rs.next();
@@ -10539,7 +10000,7 @@ public void testBug86741() throws Exception {
assertEquals(1, this.rs.getInt(2), "Wrong @@session.autocommit");
testConn.close();
- testConn = getSourceReplicaReplicationConnection();
+ testConn = getSourceReplicaReplicationConnection(props);
assertTrue(testConn.getAutoCommit(), "Wrong connection autocommit state");
this.rs = testConn.createStatement().executeQuery("SELECT @@global.autocommit, @@session.autocommit");
this.rs.next();
@@ -10563,7 +10024,7 @@ public void testBug90753() throws Exception {
int seconds = 2;
Properties props = new Properties();
- props.setProperty(PropertyKey.useSSL.getKeyName(), "false");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
try {
getConnectionWithProps(props).createStatement().executeUpdate("SET @@global.wait_timeout=" + seconds + ", @@global.interactive_timeout=" + seconds);
@@ -10630,6 +10091,8 @@ public Void call() throws Exception {
@Test
public void testBug91421() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.zeroDateTimeBehavior.getKeyName(), "exception"); // legacy EXCEPTION alias
JdbcConnection con = (JdbcConnection) getConnectionWithProps(props);
@@ -10646,8 +10109,11 @@ public void testBug91421() throws Exception {
String user = mainConnectionUrl.getDefaultUser() == null ? "" : mainConnectionUrl.getMainHost().getUser();
String password = mainConnectionUrl.getDefaultPassword() == null ? "" : mainConnectionUrl.getMainHost().getPassword();
- con = (JdbcConnection) getConnectionWithProps("jdbc:mysql://(port=" + getPortFromTestsuiteUrl() + ",user=" + user + ",password=" + password
- + ",zeroDateTimeBehavior=convertToNull)/" + this.dbName, appendRequiredProperties(null));
+ props.clear();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ con = (JdbcConnection) getConnectionWithProps("jdbc:mysql://(host=" + getHostFromTestsuiteUrl() + ",port=" + getPortFromTestsuiteUrl() + ",user=" + user
+ + ",password=" + password + ",zeroDateTimeBehavior=convertToNull)/" + this.dbName, appendRequiredProperties(props));
assertEquals(ZeroDatetimeBehavior.CONVERT_TO_NULL,
con.getPropertySet().getEnumProperty(PropertyKey.zeroDateTimeBehavior).getValue());
}
@@ -10664,13 +10130,15 @@ public void testBug28150662() throws Exception {
String password = hostInfo.getPassword() == null ? "" : hostInfo.getPassword();
List connStr = new ArrayList<>();
- connStr.add(dbUrl + "&sessionVariables=sql_mode='IGNORE_SPACE,ANSI',FOREIGN_KEY_CHECKS=0&connectionCollation=utf8mb4_unicode_ci");
- connStr.add(dbUrl + "&connectionCollation=utf8mb4_unicode_ci&sessionVariables=sql_mode='IGNORE_SPACE,ANSI',FOREIGN_KEY_CHECKS=0");
+ connStr.add(dbUrl
+ + "&sessionVariables=sql_mode='IGNORE_SPACE,ANSI',FOREIGN_KEY_CHECKS=0&connectionCollation=utf8mb4_unicode_ci&sslMode=DISABLED&allowPublicKeyRetrieval=true");
+ connStr.add(dbUrl
+ + "&connectionCollation=utf8mb4_unicode_ci&sslMode=DISABLED&allowPublicKeyRetrieval=true&sessionVariables=sql_mode='IGNORE_SPACE,ANSI',FOREIGN_KEY_CHECKS=0");
connStr.add(String.format(
- "jdbc:mysql://address=(host=%1$s)(port=%2$d)(connectionCollation=utf8mb4_unicode_ci)(sessionVariables=sql_mode='IGNORE_SPACE,ANSI',FOREIGN_KEY_CHECKS=0)(user=%3$s)(password=%4$s)/%5$s",
+ "jdbc:mysql://address=(host=%1$s)(port=%2$d)(sslMode=DISABLED)(allowPublicKeyRetrieval=true)(connectionCollation=utf8mb4_unicode_ci)(sessionVariables=sql_mode='IGNORE_SPACE,ANSI',FOREIGN_KEY_CHECKS=0)(user=%3$s)(password=%4$s)/%5$s",
getEncodedHostFromTestsuiteUrl(), getPortFromTestsuiteUrl(), user, password, hostInfo.getDatabase()));
connStr.add(String.format(
- "jdbc:mysql://(host=%1$s,port=%2$d,connectionCollation=utf8mb4_unicode_ci,sessionVariables=sql_mode='IGNORE_SPACE%3$sANSI'%3$sFOREIGN_KEY_CHECKS=0,user=%4$s,password=%5$s)/%6$s",
+ "jdbc:mysql://(host=%1$s,port=%2$d,connectionCollation=utf8mb4_unicode_ci,sslMode=DISABLED,allowPublicKeyRetrieval=true,sessionVariables=sql_mode='IGNORE_SPACE%3$sANSI'%3$sFOREIGN_KEY_CHECKS=0,user=%4$s,password=%5$s)/%6$s",
getEncodedHostFromTestsuiteUrl(), getPortFromTestsuiteUrl(), "%2C", user, password, hostInfo.getDatabase()));
for (String cs : connStr) {
@@ -10694,6 +10162,13 @@ public void testBug28150662() throws Exception {
*/
@Test
public void testBug27102307() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
// Basic SSL properties translation is tested in testBug21947042(). Testing only missing variants here.
System.setProperty("javax.net.ssl.trustStore", "");
System.setProperty("javax.net.ssl.trustStorePassword", "");
@@ -10854,6 +10329,8 @@ public void testBug89948() throws Exception {
allowMQ ? "Y" : "N", rwBatchStmts ? "Y" : "N", useLTS ? "Y" : "N", useLSS ? "Y" : "N");
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.allowMultiQueries.getKeyName(), Boolean.toString(allowMQ));
props.setProperty(PropertyKey.rewriteBatchedStatements.getKeyName(), Boolean.toString(rwBatchStmts));
props.setProperty(PropertyKey.useLocalTransactionState.getKeyName(), Boolean.toString(useLTS));
@@ -10924,68 +10401,6 @@ private void testBug89948Check(String testCase, int expectedCount, int idOffset)
assertEquals(expectedCount, c, testCase);
}
- /**
- * Tests fix for Bug#91317 (28207422), Wrong defaults on collation mappings.
- *
- * @throws Exception
- */
- @Test
- public void testBug91317() throws Exception {
- Map defaultCollations = new HashMap<>();
-
- // Compare server-side and client-side collation defaults.
- this.rs = this.stmt.executeQuery("SELECT COLLATION_NAME, CHARACTER_SET_NAME, ID FROM INFORMATION_SCHEMA.COLLATIONS WHERE IS_DEFAULT = 'Yes'");
- while (this.rs.next()) {
- String collationName = this.rs.getString(1);
- String charsetName = this.rs.getString(2);
- int collationId = this.rs.getInt(3);
- int mappedCollationId = CharsetMapping.CHARSET_NAME_TO_COLLATION_INDEX.get(charsetName);
-
- defaultCollations.put(charsetName, collationName);
-
- // Default collation for 'utf8mb4' is 'utf8mb4_0900_ai_ci' in MySQL 8.0.1 and above, 'utf8mb4_general_ci' in the others.
- if ("utf8mb4".equalsIgnoreCase(charsetName) && !versionMeetsMinimum(8, 0, 1)) {
- mappedCollationId = 45;
- }
-
- assertEquals(collationId, mappedCollationId);
- assertEquals(collationName, CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[mappedCollationId]);
- }
-
- ServerVersion sv = ((JdbcConnection) this.conn).getServerVersion();
-
- // Check `collation_connection` for each one of the known character sets.
- this.rs = this.stmt.executeQuery("SELECT character_set_name FROM information_schema.character_sets");
- int csCount = 0;
- while (this.rs.next()) {
- csCount++;
- String cs = this.rs.getString(1);
-
- // The following cannot be set as client_character_set
- // (https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html#charset-connection-impermissible-client-charset)
- if (cs.equalsIgnoreCase("ucs2") || cs.equalsIgnoreCase("utf16") || cs.equalsIgnoreCase("utf16le") || cs.equalsIgnoreCase("utf32")) {
- continue;
- }
-
- String javaEnc = CharsetMapping.getJavaEncodingForMysqlCharset(cs);
- String charsetForJavaEnc = CharsetMapping.getMysqlCharsetForJavaEncoding(javaEnc, sv);
- String expectedCollation = defaultCollations.get(charsetForJavaEnc);
-
- if ("UTF-8".equalsIgnoreCase(javaEnc)) {
- // UTF-8 is the exception. This encoding is converted to MySQL charset 'utf8mb4' instead of 'utf8', and its corresponding collation.
- expectedCollation = versionMeetsMinimum(8, 0, 1) ? "utf8mb4_0900_ai_ci" : "utf8mb4_general_ci";
- }
-
- Connection testConn = getConnectionWithProps("characterEncoding=" + javaEnc);
- ResultSet testRs = testConn.createStatement().executeQuery("SHOW VARIABLES LIKE 'collation_connection'");
- assertTrue(testRs.next());
- assertEquals(expectedCollation, testRs.getString(2));
- testConn.close();
- }
- // Assert that some charsets were tested.
- assertTrue(csCount > 35); // There are 39 charsets in MySQL 5.5.61, 40 in MySQL 5.6.41 and 41 in MySQL 5.7.23 and above, but these numbers can vary.
- }
-
/**
* Tests fix for Bug#25642226, CHANGEUSER() NOT SETTING THE DATABASE PROPERLY WITH SHA USER.
*
@@ -10993,37 +10408,30 @@ public void testBug91317() throws Exception {
*/
@Test
public void testBug25642226() throws Exception {
- testBug25642226Task(dbUrl, "\u4F5C\u4F5C\u4F5C");
- testBug25642226Task(sha256Url, "\u4F5C\u4F5C\u4F5C");
- }
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 6, 5), "Requires MySQL 5.6.5+ server.");
+ assumeTrue(pluginIsActive(this.stmt, "sha256_password"), "sha256_password required to run this test");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
+ String pwd = "\u4F5C\u4F5C\u4F5C";
- private void testBug25642226Task(String url, String pwd) throws Exception {
final Properties props = new Properties();
- props.setProperty(PropertyKey.sslMode.getKeyName(), "REQUIRED");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
props.setProperty(PropertyKey.trustCertificateKeyStoreUrl.getKeyName(), "file:src/test/config/ssl-test-certs/ca-truststore");
props.setProperty(PropertyKey.trustCertificateKeyStorePassword.getKeyName(), "password");
props.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8");
- Connection c1 = getConnectionWithProps(url, props);
+ Connection c1 = getConnectionWithProps(dbUrl, props);
Connection c2 = null;
Session sess = ((JdbcConnection) c1).getSession();
-
- if (!sess.versionMeetsMinimum(5, 6, 5)) {
- System.out.println("Skipped. Requires MySQL 5.6.5+ server.");
- c1.close();
- return;
- }
-
Statement s1 = c1.createStatement();
- if (!pluginIsActive(s1, "sha256_password")) {
- c1.close();
- fail("sha256_password required to run this test");
- }
this.rs = s1.executeQuery("select database()");
this.rs.next();
String origDb = this.rs.getString(1);
- System.out.println("URL [" + url + "]");
+ System.out.println("URL [" + dbUrl + "]");
System.out.println("1. Original database [" + origDb + "]");
try {
@@ -11039,7 +10447,7 @@ private void testBug25642226Task(String url, String pwd) throws Exception {
: "set password for 'Bug25642226u1'@'%' = PASSWORD('" + pwd + "')");
s1.executeUpdate("flush privileges");
- c2 = getConnectionWithProps(url, props);
+ c2 = getConnectionWithProps(dbUrl, props);
Statement s2 = c2.createStatement();
((JdbcConnection) c2).changeUser("Bug25642226u1", pwd);
@@ -11051,9 +10459,7 @@ private void testBug25642226Task(String url, String pwd) throws Exception {
// create user with required password and caching_sha2_password auth
if (sess.versionMeetsMinimum(8, 0, 3)) {
- if (!pluginIsActive(s1, "caching_sha2_password")) {
- fail("caching_sha2_password required to run this test");
- }
+ assertTrue(pluginIsActive(s1, "caching_sha2_password"), "caching_sha2_password required to run this test");
// create user with required password and sha256_password auth
createUser(s1, "'Bug25642226u2'@'%'", "identified WITH caching_sha2_password");
s1.executeUpdate("grant all on *.* to 'Bug25642226u2'@'%'");
@@ -11092,6 +10498,8 @@ private void testBug25642226Task(String url, String pwd) throws Exception {
@Test
public void testBug92625() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "true");
Connection con = getConnectionWithProps(props);
@@ -11112,7 +10520,7 @@ public Void call() throws Exception {
@Test
public void testBug25642021() throws Exception {
Properties props = getPropertiesFromTestsuiteUrl();
- props.setProperty(PropertyKey.sslMode.getKeyName(), "DISABLED");
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.enablePacketDebug.getKeyName(), "true");
props.setProperty(PropertyKey.maintainTimeStats.getKeyName(), "true");
@@ -11145,6 +10553,8 @@ public void testBug25642021() throws Exception {
@Test
public void testBug93007() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), ForcedLoadBalanceStrategy.class.getName());
props.setProperty(PropertyKey.loadBalanceBlocklistTimeout.getKeyName(), "5000");
props.setProperty(PropertyKey.loadBalancePingTimeout.getKeyName(), "100");
@@ -11202,6 +10612,8 @@ public void testBug93007() throws Exception {
@Test
public void testBug29329326() throws Exception {
Properties p = new Properties();
+ p.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ p.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug29329326QueryInterceptor.class.getName());
JdbcConnection c = (JdbcConnection) getConnectionWithProps(p);
@@ -11316,6 +10728,8 @@ public void testBug74690() throws Exception {
@Test
public void testBug70677() throws Exception {
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
props.setProperty(PropertyKey.logger.getKeyName(), BufferingLogger.class.getName());
BufferingLogger.startLoggingToBuffer();
@@ -11347,8 +10761,14 @@ public void testBug70677() throws Exception {
public void testBug98445() throws Exception {
createProcedure("setCiTestBug98445", "(IN k VARCHAR(100), IN v VARCHAR(100)) BEGIN SET @testBug98445=v; END");
+ Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+
// clientInfoProvider=ClientInfoProviderSP
- Connection testConn1 = getConnectionWithProps("clientInfoProvider=ClientInfoProviderSP,clientInfoSetSPName=setCiTestBug98445");
+ props.setProperty(PropertyKey.clientInfoProvider.getKeyName(), "ClientInfoProviderSP");
+ props.setProperty(ClientInfoProviderSP.PNAME_clientInfoSetSPName, "setCiTestBug98445");
+ Connection testConn1 = getConnectionWithProps(props);
testConn1.setClientInfo("testBug98445", "testBug98445Data1");
Statement testStmt = testConn1.createStatement();
this.rs = testStmt.executeQuery("SELECT @testBug98445");
@@ -11357,7 +10777,9 @@ public void testBug98445() throws Exception {
testConn1.close();
// clientInfoProvider=com.mysql.cj.jdbc.ClientInfoProviderSP
- testConn1 = getConnectionWithProps("clientInfoProvider=com.mysql.cj.jdbc.ClientInfoProviderSP,clientInfoSetSPName=setCiTestBug98445");
+ props.setProperty(PropertyKey.clientInfoProvider.getKeyName(), ClientInfoProviderSP.class.getName());
+ props.setProperty(ClientInfoProviderSP.PNAME_clientInfoSetSPName, "setCiTestBug98445");
+ testConn1 = getConnectionWithProps(props);
testConn1.setClientInfo("testBug98445", "testBug98445Data2");
testStmt = testConn1.createStatement();
this.rs = testStmt.executeQuery("SELECT @testBug98445");
@@ -11370,7 +10792,10 @@ public void testBug98445() throws Exception {
System.setErr(new PrintStream(newErr));
// clientInfoProvider=CommentClientInfoProvider
- testConn1 = getConnectionWithProps("clientInfoProvider=CommentClientInfoProvider,profileSQL=true");
+ props.setProperty(PropertyKey.clientInfoProvider.getKeyName(), "CommentClientInfoProvider");
+ props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
+ props.remove("clientInfoSetSPName");
+ testConn1 = getConnectionWithProps(props);
testConn1.setClientInfo("testBug98445", "testBug98445Data3");
testStmt = testConn1.createStatement();
this.rs = testStmt.executeQuery("SELECT 'testBug98445Data3'");
@@ -11383,7 +10808,9 @@ public void testBug98445() throws Exception {
newErr.reset();
// clientInfoProvider=com.mysql.cj.jdbc.CommentClientInfoProvider
- testConn1 = getConnectionWithProps("clientInfoProvider=com.mysql.cj.jdbc.CommentClientInfoProvider,profileSQL=true");
+ props.setProperty(PropertyKey.clientInfoProvider.getKeyName(), CommentClientInfoProvider.class.getName());
+ props.setProperty(PropertyKey.profileSQL.getKeyName(), "true");
+ testConn1 = getConnectionWithProps(props);
testConn1.setClientInfo("testBug98445", "testBug98445Data4");
testStmt = testConn1.createStatement();
this.rs = testStmt.executeQuery("SELECT 'testBug98445Data4'");
@@ -11397,7 +10824,9 @@ public void testBug98445() throws Exception {
System.setErr(oldErr);
// clientInfoProvider=TestBug98445ClientInfoProvider
- testConn1 = getConnectionWithProps("clientInfoProvider=" + TestBug98445ClientInfoProvider.class.getName());
+ props.setProperty(PropertyKey.clientInfoProvider.getKeyName(), TestBug98445ClientInfoProvider.class.getName());
+ props.remove(PropertyKey.profileSQL.getKeyName());
+ testConn1 = getConnectionWithProps(props);
testConn1.setClientInfo("testBug98445", "testBug98445Data7");
testStmt = testConn1.createStatement();
this.rs = testStmt.executeQuery("SELECT @testBug98445");
@@ -11406,7 +10835,8 @@ public void testBug98445() throws Exception {
testConn1.close();
// clientInfoProvider=DummyClass
- Connection testConn2 = getConnectionWithProps("clientInfoProvider=DummyClass");
+ props.setProperty(PropertyKey.clientInfoProvider.getKeyName(), "DummyClass");
+ Connection testConn2 = getConnectionWithProps(props);
Throwable t = assertThrows(SQLClientInfoException.class, () -> {
testConn2.setClientInfo("testBug98445", "testBug98445Data5");
return null;
@@ -11416,7 +10846,8 @@ public void testBug98445() throws Exception {
testConn2.close();
// clientInfoProvider=java.lang.Object
- Connection testConn3 = getConnectionWithProps("clientInfoProvider=java.lang.Object");
+ props.setProperty(PropertyKey.clientInfoProvider.getKeyName(), Object.class.getName());
+ Connection testConn3 = getConnectionWithProps(props);
t = assertThrows(SQLClientInfoException.class, () -> {
testConn3.setClientInfo("testBug98445", "testBug98445Data6");
return null;
@@ -11467,13 +10898,16 @@ public void setClientInfo(Connection conn, String name, String value) throws SQL
*/
@Test
public void testBug97714() throws Exception {
+ assumeFalse(isServerRunningOnWindows(), "SLEEP() is not precise enough on Windows.");
boolean useSPS = false;
do {
final String testCase = String.format("Case: [useServerPrepStmts: %s]", useSPS ? "Y" : "N");
Properties props = new Properties();
- props.setProperty("useServerPrepStmts", Boolean.toString(useSPS));
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
+ props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), Boolean.toString(useSPS));
Connection testConn = getConnectionWithProps(props);
// Statement
@@ -11514,6 +10948,13 @@ public void testBug97714() throws Exception {
*/
@Test
public void testBug99767() throws Exception {
+ assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0,
+ "This test requires server with SSL support.");
+ assumeTrue(supportsTLSv1_2(((MysqlConnection) this.conn).getSession().getServerSession().getServerVersion()),
+ "This test requires server with TLSv1.2+ support.");
+ assumeTrue(supportsTestCertificates(this.stmt),
+ "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
+
try {
final Properties props = getPropertiesFromTestsuiteUrl();
props.setProperty(PropertyKey.socketFactory.getKeyName(), "testsuite.UnreliableSocketFactory");
@@ -11580,14 +11021,10 @@ public void testBug99767() throws Exception {
*/
@Test
public void testBug99076() throws Exception {
- if (!versionMeetsMinimum(8, 0, 16)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(8, 0, 16), "MySQL 8.0.16+ is required to run this test.");
String xUrl = System.getProperty(PropertyDefinitions.SYSP_testsuite_url_mysqlx);
- if (xUrl == null || xUrl.length() == 0) {
- return;
- }
+ assumeTrue(xUrl != null && xUrl.length() != 0, PropertyDefinitions.SYSP_testsuite_url_mysqlx + " must be set to run this test.");
final ConnectionUrl conUrl = ConnectionUrl.getConnectionUrlInstance(xUrl, null);
final HostInfo hostInfo = conUrl.getMainHost();
@@ -11607,15 +11044,16 @@ public void testBug99076() throws Exception {
*/
@Test
public void testBug98667() throws Exception {
+ assumeTrue(isServerRunningOnWindows() && isMysqlRunningLocally(),
+ "This test can run only when client and server are running on the same Windows host.");
+
this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'named_pipe'");
- if (!this.rs.next() || !this.rs.getString(2).equalsIgnoreCase("on")) {
- return; // Only runs on Windows with named pipes enabled.
- }
+ assumeTrue(this.rs.next() && this.rs.getString(2).equalsIgnoreCase("on"), "Only runs on Windows with named_pipe=ON.");
+ String namedPipeName = null;
this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'socket'");
- assumeTrue(this.rs.next());
- String namedPipeName = this.rs.getString(2);
- assumeFalse(StringUtils.isNullOrEmpty(namedPipeName));
+ assumeTrue(this.rs.next() && !StringUtils.isNullOrEmpty(namedPipeName = this.rs.getString(2)),
+ "Only runs on Windows with enabled named pipes and not empty socket name.");
final String namedPipePath = "\\\\.\\pipe\\" + namedPipeName;
final Properties props = getHostFreePropertiesFromTestsuiteUrl();
@@ -11667,6 +11105,8 @@ public void testBug21789378() throws Exception {
f.setAccessible(true);
Properties props = new Properties();
+ props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
+ props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.cacheDefaultTimeZone.getKeyName(), "false");
props.setProperty(PropertyKey.connectionTimeZone.getKeyName(), "SERVER");
@@ -11689,31 +11129,27 @@ public void testBug21789378() throws Exception {
*/
@Test
public void testDefaultUserWithoutPasswordAuthentication() throws Exception {
- if (!versionMeetsMinimum(5, 5, 7)) {
- return;
- }
+ assumeTrue(versionMeetsMinimum(5, 5, 7), "MySQL 5.5.7+ is required to run this test.");
String systemUsername = System.getProperty("user.name");
- if (StringUtils.isNullOrEmpty(systemUsername)) {
- return;
- }
+ assumeFalse(StringUtils.isNullOrEmpty(systemUsername), "This test can't proceed with empty system user name.");
this.rs = this.stmt.executeQuery("SELECT user FROM mysql.user WHERE user = '" + systemUsername + "'");
- assumeFalse(this.rs.next()); // Probably user 'root' and there is one already. This test can't mess with it.
+ assumeFalse(this.rs.next(), "Probably user 'root' and there is one already. This test can't proceed with it.");
String[] authenticationPlugins = new String[] { "caching_sha2_password", "sha256_password", "mysql_native_password" };
List