in src/main/core-impl/java/com/mysql/cj/NativeSession.java [365:595]
public boolean configureClientCharacterSet(boolean dontCheckServerMatch) {
String realJavaEncoding = this.characterEncoding.getValue();
RuntimeProperty<String> characterSetResults = getPropertySet().getProperty(PropertyKey.characterSetResults);
boolean characterSetAlreadyConfigured = false;
try {
characterSetAlreadyConfigured = true;
configureCharsetProperties();
realJavaEncoding = this.characterEncoding.getValue(); // we need to do this again to grab this for versions > 4.1.0
String connectionCollationSuffix = "";
String connectionCollationCharset = null;
String connectionCollation = getPropertySet().getStringProperty(PropertyKey.connectionCollation).getStringValue();
if (connectionCollation != null) {
for (int i = 1; i < CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length; i++) {
if (CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[i].equals(connectionCollation)) {
connectionCollationSuffix = " COLLATE " + CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[i];
connectionCollationCharset = CharsetMapping.COLLATION_INDEX_TO_CHARSET[i].charsetName;
realJavaEncoding = CharsetMapping.getJavaEncodingForCollationIndex(i);
}
}
}
try {
String serverEncodingToSet = CharsetMapping.getJavaEncodingForCollationIndex(this.protocol.getServerSession().getServerDefaultCollationIndex());
if (serverEncodingToSet == null || serverEncodingToSet.length() == 0) {
if (realJavaEncoding != null) {
// user knows best, try it
this.characterEncoding.setValue(realJavaEncoding);
} else {
throw ExceptionFactory.createException(
Messages.getString("Connection.6", new Object[] { this.protocol.getServerSession().getServerDefaultCollationIndex() }),
getExceptionInterceptor());
}
}
// "latin1" on MySQL-4.1.0+ is actually CP1252, not ISO8859_1
if ("ISO8859_1".equalsIgnoreCase(serverEncodingToSet)) {
serverEncodingToSet = "Cp1252";
}
if ("UnicodeBig".equalsIgnoreCase(serverEncodingToSet) || "UTF-16".equalsIgnoreCase(serverEncodingToSet)
|| "UTF-16LE".equalsIgnoreCase(serverEncodingToSet) || "UTF-32".equalsIgnoreCase(serverEncodingToSet)) {
serverEncodingToSet = "UTF-8";
}
this.characterEncoding.setValue(serverEncodingToSet);
} catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
if (realJavaEncoding != null) {
// user knows best, try it
this.characterEncoding.setValue(realJavaEncoding);
} else {
throw ExceptionFactory.createException(
Messages.getString("Connection.6", new Object[] { this.protocol.getServerSession().getServerDefaultCollationIndex() }),
getExceptionInterceptor());
}
}
if (this.characterEncoding.getValue() == null) {
// punt?
this.characterEncoding.setValue("ISO8859_1");
}
if (realJavaEncoding != null) {
//
// Now, inform the server what character set we will be using from now-on...
//
if (realJavaEncoding.equalsIgnoreCase("UTF-8") || realJavaEncoding.equalsIgnoreCase("UTF8")) {
// charset names are case-sensitive
String utf8CharsetName = connectionCollationSuffix.length() > 0 ? connectionCollationCharset : "utf8mb4";
if (dontCheckServerMatch || !this.protocol.getServerSession().characterSetNamesMatches("utf8")
|| (!this.protocol.getServerSession().characterSetNamesMatches("utf8mb4")) || (connectionCollationSuffix.length() > 0
&& !connectionCollation.equalsIgnoreCase(this.protocol.getServerSession().getServerVariable("collation_server")))) {
sendCommand(this.commandBuilder.buildComQuery(null, "SET NAMES " + utf8CharsetName + connectionCollationSuffix), false, 0);
this.protocol.getServerSession().getServerVariables().put("character_set_client", utf8CharsetName);
this.protocol.getServerSession().getServerVariables().put("character_set_connection", utf8CharsetName);
}
this.characterEncoding.setValue(realJavaEncoding);
} /* not utf-8 */else {
String mysqlCharsetName = connectionCollationSuffix.length() > 0 ? connectionCollationCharset
: CharsetMapping.getMysqlCharsetForJavaEncoding(realJavaEncoding.toUpperCase(Locale.ENGLISH),
getServerSession().getServerVersion());
if (mysqlCharsetName != null) {
if (dontCheckServerMatch || !this.protocol.getServerSession().characterSetNamesMatches(mysqlCharsetName)) {
sendCommand(this.commandBuilder.buildComQuery(null, "SET NAMES " + mysqlCharsetName + connectionCollationSuffix), false, 0);
this.protocol.getServerSession().getServerVariables().put("character_set_client", mysqlCharsetName);
this.protocol.getServerSession().getServerVariables().put("character_set_connection", mysqlCharsetName);
}
}
// Switch driver's encoding now, since the server knows what we're sending...
//
this.characterEncoding.setValue(realJavaEncoding);
}
} else if (this.characterEncoding.getValue() != null) {
// Tell the server we'll use the server default charset to send our queries from now on....
String mysqlCharsetName = connectionCollationSuffix.length() > 0 ? connectionCollationCharset : getServerSession().getServerDefaultCharset();
boolean ucs2 = false;
if ("ucs2".equalsIgnoreCase(mysqlCharsetName) || "utf16".equalsIgnoreCase(mysqlCharsetName) || "utf16le".equalsIgnoreCase(mysqlCharsetName)
|| "utf32".equalsIgnoreCase(mysqlCharsetName)) {
mysqlCharsetName = "utf8";
ucs2 = true;
if (characterSetResults.getValue() == null) {
characterSetResults.setValue("UTF-8");
}
}
if (dontCheckServerMatch || !this.protocol.getServerSession().characterSetNamesMatches(mysqlCharsetName) || ucs2) {
sendCommand(this.commandBuilder.buildComQuery(null, "SET NAMES " + mysqlCharsetName + connectionCollationSuffix), false, 0);
this.protocol.getServerSession().getServerVariables().put("character_set_client", mysqlCharsetName);
this.protocol.getServerSession().getServerVariables().put("character_set_connection", mysqlCharsetName);
}
realJavaEncoding = this.characterEncoding.getValue();
}
//
// 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 onServer = this.protocol.getServerSession().getServerVariable("character_set_results");
if (characterSetResults.getValue() == null) {
//
// Only send if needed, if we're caching server variables we -have- to send, because we don't know what it was before we cached them.
//
if (onServer != null && onServer.length() > 0 && !"NULL".equalsIgnoreCase(onServer)) {
sendCommand(this.commandBuilder.buildComQuery(null, "SET character_set_results = NULL"), false, 0);
this.protocol.getServerSession().getServerVariables().put(ServerSession.LOCAL_CHARACTER_SET_RESULTS, null);
} else {
this.protocol.getServerSession().getServerVariables().put(ServerSession.LOCAL_CHARACTER_SET_RESULTS, onServer);
}
} else {
String charsetResults = characterSetResults.getValue();
String mysqlEncodingName = null;
if ("UTF-8".equalsIgnoreCase(charsetResults) || "UTF8".equalsIgnoreCase(charsetResults)) {
mysqlEncodingName = "utf8";
} else if ("null".equalsIgnoreCase(charsetResults)) {
mysqlEncodingName = "NULL";
} else {
mysqlEncodingName = CharsetMapping.getMysqlCharsetForJavaEncoding(charsetResults.toUpperCase(Locale.ENGLISH),
getServerSession().getServerVersion());
}
//
// Only change the value if needed
//
if (mysqlEncodingName == null) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.7", new Object[] { charsetResults }),
getExceptionInterceptor());
}
if (!mysqlEncodingName.equalsIgnoreCase(this.protocol.getServerSession().getServerVariable("character_set_results"))) {
StringBuilder setBuf = new StringBuilder("SET character_set_results = ".length() + mysqlEncodingName.length());
setBuf.append("SET character_set_results = ").append(mysqlEncodingName);
sendCommand(this.commandBuilder.buildComQuery(null, setBuf.toString()), false, 0);
this.protocol.getServerSession().getServerVariables().put(ServerSession.LOCAL_CHARACTER_SET_RESULTS, mysqlEncodingName);
// We have to set errorMessageEncoding according to new value of charsetResults for server version 5.5 and higher
this.protocol.getServerSession().setErrorMessageEncoding(charsetResults);
} else {
this.protocol.getServerSession().getServerVariables().put(ServerSession.LOCAL_CHARACTER_SET_RESULTS, onServer);
}
}
} finally {
// Failsafe, make sure that the driver's notion of character encoding matches what the user has specified.
//
this.characterEncoding.setValue(realJavaEncoding);
}
/**
* 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;
}
}
}
return characterSetAlreadyConfigured;
}