in src/main/core-impl/java/com/mysql/cj/NativeCharsetSettings.java [255:429]
public void configurePostHandshake(boolean dontCheckServerMatch) {
buildCollationMapping();
/*
* Configuring characterEncoding.
*/
String requiredCollation = this.connectionCollation.getStringValue();
String requiredEncoding = this.characterEncoding.getValue();
String passwordEncoding = this.passwordCharacterEncoding.getValue();
Integer requiredCollationIndex;
String sessionCharsetName = getServerDefaultCharset();
String sessionCollationClause = "";
try {
// connectionCollation overrides the characterEncoding value
if (requiredCollation != null && (requiredCollationIndex = getCollationIndexForCollationName(requiredCollation)) != null) {
if (isImpermissibleCollation(requiredCollationIndex)) {
if (this.serverSession.getCapabilities().getServerVersion().meetsMinimum(new ServerVersion(8, 0, 1))) {
requiredCollationIndex = MYSQL_COLLATION_INDEX_utf8mb4_0900_ai_ci;
requiredCollation = "utf8mb4_0900_ai_ci";
} else {
requiredCollationIndex = MYSQL_COLLATION_INDEX_utf8mb4_general_ci;
requiredCollation = "utf8mb4_general_ci";
}
}
sessionCollationClause = " COLLATE " + requiredCollation;
sessionCharsetName = getMysqlCharsetNameForCollationIndex(requiredCollationIndex);
requiredEncoding = getJavaEncodingForCollationIndex(requiredCollationIndex, requiredEncoding);
this.sessionCollationIndex = requiredCollationIndex;
}
if (requiredEncoding != null) { // If either connectionCollation or characterEncoding is defined.
if (sessionCollationClause.length() == 0) { // If no connectionCollation is defined.
sessionCharsetName = getMysqlCharsetForJavaEncoding(requiredEncoding.toUpperCase(Locale.ENGLISH), this.serverSession.getServerVersion());
}
} else { // Neither connectionCollation nor characterEncoding are defined.
// Collations with index > 255 don't fit into server greeting packet.
// Now we can set sessionCollationIndex according to "collation_server" value.
if (!StringUtils.isNullOrEmpty(passwordEncoding)) {
if (this.serverSession.getCapabilities().getServerVersion().meetsMinimum(new ServerVersion(8, 0, 1))) {
this.sessionCollationIndex = MYSQL_COLLATION_INDEX_utf8mb4_0900_ai_ci; // We can't do more, just trying to use utf8mb4_0900_ai_ci because the most of collations in that range are utf8mb4.
requiredCollation = "utf8mb4_0900_ai_ci";
} else {
this.sessionCollationIndex = MYSQL_COLLATION_INDEX_utf8mb4_general_ci;
requiredCollation = "utf8mb4_general_ci";
}
sessionCollationClause = " COLLATE " + getCollationNameForCollationIndex(this.sessionCollationIndex);
}
if ((requiredEncoding = getJavaEncodingForCollationIndex(this.sessionCollationIndex, requiredEncoding)) == null) {
// if there is no mapping for default collation index leave characterEncoding as specified by user
throw ExceptionFactory.createException(Messages.getString("Connection.5", new Object[] { this.sessionCollationIndex.toString() }),
this.session.getExceptionInterceptor());
}
sessionCharsetName = getMysqlCharsetNameForCollationIndex(this.sessionCollationIndex);
}
} catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
throw ExceptionFactory.createException(Messages.getString("Connection.6", new Object[] { this.sessionCollationIndex }),
this.session.getExceptionInterceptor());
}
this.characterEncoding.setValue(requiredEncoding);
if (sessionCharsetName != null) {
boolean isCharsetDifferent = !characterSetNamesMatches(sessionCharsetName);
boolean isCollationDifferent = sessionCollationClause.length() > 0
&& !requiredCollation.equalsIgnoreCase(this.serverSession.getServerVariable(COLLATION_CONNECTION));
if (dontCheckServerMatch || isCharsetDifferent || isCollationDifferent) {
String sql = "SET NAMES " + sessionCharsetName + sessionCollationClause;
telemetryWrapSendCommand(() -> this.session.getProtocol().sendCommand(getCommandBuilder().buildComQuery(null, this.session, sql), false, 0),
TelemetrySpanName.SET_CHARSET);
this.serverSession.getServerVariables().put(CHARACTER_SET_CLIENT, sessionCharsetName);
this.serverSession.getServerVariables().put(CHARACTER_SET_CONNECTION, sessionCharsetName);
if (sessionCollationClause.length() > 0) {
this.serverSession.getServerVariables().put(COLLATION_CONNECTION, requiredCollation);
} else {
int idx = getCollationIndexForMysqlCharsetName(sessionCharsetName);
if (idx == MYSQL_COLLATION_INDEX_utf8mb4_0900_ai_ci
&& !this.serverSession.getCapabilities().getServerVersion().meetsMinimum(new ServerVersion(8, 0, 1))) {
idx = MYSQL_COLLATION_INDEX_utf8mb4_general_ci;
}
this.serverSession.getServerVariables().put(COLLATION_CONNECTION, getCollationNameForCollationIndex(idx));
}
}
}
/*
* Configuring characterSetResults.
*
* We know how to deal with any charset coming back from the database, so tell the server not to do conversion
* if the user hasn't 'forced' a result-set character set.
*/
String sessionResultsCharset = this.serverSession.getServerVariable(CHARACTER_SET_RESULTS);
String characterSetResultsValue = this.characterSetResults.getValue();
if (StringUtils.isNullOrEmpty(characterSetResultsValue) || "null".equalsIgnoreCase(characterSetResultsValue)) {
if (!StringUtils.isNullOrEmpty(sessionResultsCharset) && !"NULL".equalsIgnoreCase(sessionResultsCharset)) {
telemetryWrapSendCommand(() -> this.session.getProtocol()
.sendCommand(getCommandBuilder().buildComQuery(null, this.session, "SET character_set_results = NULL"), false, 0),
TelemetrySpanName.SET_VARIABLE, "character_set_results");
this.serverSession.getServerVariables().put(CHARACTER_SET_RESULTS, null);
}
String defaultMetadataCharsetMysql = this.serverSession.getServerVariable("character_set_system");
this.metadataEncoding = defaultMetadataCharsetMysql != null ? getJavaEncodingForMysqlCharset(defaultMetadataCharsetMysql) : "UTF-8";
this.errorMessageEncoding = "UTF-8";
} else {
String resultsCharsetName = getMysqlCharsetForJavaEncoding(characterSetResultsValue.toUpperCase(Locale.ENGLISH),
this.serverSession.getServerVersion());
if (resultsCharsetName == null) {
throw ExceptionFactory.createException(WrongArgumentException.class,
Messages.getString("Connection.7", new Object[] { characterSetResultsValue }), this.session.getExceptionInterceptor());
}
if (!resultsCharsetName.equalsIgnoreCase(sessionResultsCharset)) {
telemetryWrapSendCommand(
() -> this.session.getProtocol().sendCommand(
getCommandBuilder().buildComQuery(null, this.session, "SET character_set_results = " + resultsCharsetName), false, 0),
TelemetrySpanName.SET_VARIABLE, "character_set_results");
this.serverSession.getServerVariables().put(CHARACTER_SET_RESULTS, resultsCharsetName);
}
this.metadataEncoding = characterSetResultsValue;
this.errorMessageEncoding = characterSetResultsValue;
}
this.metadataCollationIndex = getCollationIndexForJavaEncoding(this.metadataEncoding, this.serverSession.getServerVersion());
checkForCharsetMismatch();
/**
* Check if we need a CharsetEncoder for escaping codepoints that are
* transformed to backslash (0x5c) in the connection encoding.
*/
try {
CharsetEncoder enc = Charset.forName(this.characterEncoding.getValue()).newEncoder();
CharBuffer cbuf = CharBuffer.allocate(1);
ByteBuffer bbuf = ByteBuffer.allocate(1);
cbuf.put("\u00a5");
cbuf.position(0);
enc.encode(cbuf, bbuf, true);
if (bbuf.get(0) == '\\') {
this.requiresEscapingEncoder = true;
} else {
cbuf.clear();
bbuf.clear();
cbuf.put("\u20a9");
cbuf.position(0);
enc.encode(cbuf, bbuf, true);
if (bbuf.get(0) == '\\') {
this.requiresEscapingEncoder = true;
}
}
} catch (java.nio.charset.UnsupportedCharsetException ucex) {
// fallback to String API
byte bbuf[] = StringUtils.getBytes("\u00a5", this.characterEncoding.getValue());
if (bbuf[0] == '\\') {
this.requiresEscapingEncoder = true;
} else {
bbuf = StringUtils.getBytes("\u20a9", this.characterEncoding.getValue());
if (bbuf[0] == '\\') {
this.requiresEscapingEncoder = true;
}
}
}
}