|
37 | 37 | import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
38 | 38 |
|
39 | 39 | import java.io.UnsupportedEncodingException;
|
| 40 | +import java.lang.reflect.Field; |
40 | 41 | import java.sql.Connection;
|
41 | 42 | import java.sql.DriverManager;
|
42 | 43 | import java.sql.PreparedStatement;
|
|
52 | 53 |
|
53 | 54 | import org.junit.jupiter.api.Test;
|
54 | 55 |
|
| 56 | +import com.mysql.cj.CacheAdapter; |
55 | 57 | import com.mysql.cj.CharsetMappingWrapper;
|
56 | 58 | import com.mysql.cj.CharsetSettings;
|
57 | 59 | import com.mysql.cj.MysqlConnection;
|
| 60 | +import com.mysql.cj.NativeSession; |
58 | 61 | import com.mysql.cj.Query;
|
59 | 62 | import com.mysql.cj.ServerVersion;
|
60 | 63 | import com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm;
|
@@ -1183,4 +1186,128 @@ public <T extends Resultset> T preProcess(Supplier<String> str, Query intercepte
|
1183 | 1186 | return null;
|
1184 | 1187 | }
|
1185 | 1188 | }
|
| 1189 | + |
| 1190 | + /** |
| 1191 | + * Tests fix for Bug#95139 (29807572), CACHESERVERCONFIGURATION APPEARS TO THWART CHARSET DETECTION. |
| 1192 | + * |
| 1193 | + * @throws Exception |
| 1194 | + */ |
| 1195 | + @Test |
| 1196 | + public void testBug95139() throws Exception { |
| 1197 | + |
| 1198 | + Properties p = new Properties(); |
| 1199 | + p.setProperty(PropertyKey.sslMode.getKeyName(), "DISABLED"); |
| 1200 | + p.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true"); |
| 1201 | + p.setProperty(PropertyKey.queryInterceptors.getKeyName(), Bug95139QueryInterceptor.class.getName()); |
| 1202 | + testBug95139CheckVariables(p, 1, null, "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL"); |
| 1203 | + |
| 1204 | + p.setProperty(PropertyKey.cacheServerConfiguration.getKeyName(), "true"); |
| 1205 | + p.setProperty(PropertyKey.detectCustomCollations.getKeyName(), "true"); |
| 1206 | + |
| 1207 | + // Empty the cache possibly created by other tests to get a correct queryVarsCnt on the next step |
| 1208 | + Connection c = getConnectionWithProps(p); |
| 1209 | + Field f = NativeSession.class.getDeclaredField("serverConfigCache"); |
| 1210 | + f.setAccessible(true); |
| 1211 | + @SuppressWarnings("unchecked") |
| 1212 | + CacheAdapter<String, Map<String, String>> cache = (CacheAdapter<String, Map<String, String>>) f.get(((MysqlConnection) c).getSession()); |
| 1213 | + if (cache != null) { |
| 1214 | + cache.invalidateAll(); |
| 1215 | + } |
| 1216 | + |
| 1217 | + p.setProperty(PropertyKey.characterEncoding.getKeyName(), "cp1252"); |
| 1218 | + p.setProperty(PropertyKey.characterSetResults.getKeyName(), "cp1252"); |
| 1219 | + testBug95139CheckVariables(p, 1, null, null); |
| 1220 | + |
| 1221 | + p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8"); |
| 1222 | + p.setProperty(PropertyKey.characterSetResults.getKeyName(), "cp1252"); |
| 1223 | + testBug95139CheckVariables(p, 0, null, "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = latin1"); |
| 1224 | + |
| 1225 | + p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8"); |
| 1226 | + p.remove(PropertyKey.characterSetResults.getKeyName()); |
| 1227 | + testBug95139CheckVariables(p, 0, null, "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL"); |
| 1228 | + |
| 1229 | + p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8"); |
| 1230 | + p.setProperty(PropertyKey.passwordCharacterEncoding.getKeyName(), "latin1"); |
| 1231 | + testBug95139CheckVariables(p, 0, "SET NAMES utf8mb4", "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL"); |
| 1232 | + |
| 1233 | + p.setProperty(PropertyKey.characterEncoding.getKeyName(), "UTF-8"); |
| 1234 | + p.setProperty(PropertyKey.passwordCharacterEncoding.getKeyName(), "latin1"); |
| 1235 | + p.setProperty(PropertyKey.connectionCollation.getKeyName(), "utf8mb4_bin"); |
| 1236 | + testBug95139CheckVariables(p, 0, "SET NAMES utf8mb4 COLLATE utf8mb4_bin", "SET " + CharsetSettings.CHARACTER_SET_RESULTS + " = NULL"); |
| 1237 | + } |
| 1238 | + |
| 1239 | + private void testBug95139CheckVariables(Properties p, int queryVarsCnt, String expSetNamesQuery, String expSetCharacterSetResultsquery) throws Exception { |
| 1240 | + Connection con = getConnectionWithProps(p); |
| 1241 | + |
| 1242 | + Bug95139QueryInterceptor si = (Bug95139QueryInterceptor) ((JdbcConnection) con).getQueryInterceptorsInstances().get(0); |
| 1243 | + assertEquals(queryVarsCnt, si.queryVarsCnt); |
| 1244 | + assertEquals(expSetNamesQuery == null ? 0 : 1, si.setNamesCnt); |
| 1245 | + assertEquals(expSetCharacterSetResultsquery == null ? 0 : 1, si.setCharacterSetResultsCnt); |
| 1246 | + if (expSetNamesQuery != null) { |
| 1247 | + assertEquals(expSetNamesQuery, si.setNamesQuery); |
| 1248 | + } |
| 1249 | + if (expSetCharacterSetResultsquery != null) { |
| 1250 | + assertEquals(expSetCharacterSetResultsquery, si.setCharacterSetResultsQuery); |
| 1251 | + } |
| 1252 | + |
| 1253 | + Map<String, String> svs = ((MysqlConnection) con).getSession().getServerSession().getServerVariables(); |
| 1254 | + System.out.println(svs); |
| 1255 | + Map<String, String> exp = new HashMap<>(); |
| 1256 | + exp.put("character_set_client", svs.get("character_set_client")); |
| 1257 | + exp.put("character_set_connection", svs.get("character_set_connection")); |
| 1258 | + exp.put("character_set_results", svs.get("character_set_results") == null ? "" : svs.get("character_set_results")); |
| 1259 | + exp.put("character_set_server", svs.get("character_set_server")); |
| 1260 | + exp.put("collation_server", svs.get("collation_server")); |
| 1261 | + exp.put("collation_connection", svs.get("collation_connection")); |
| 1262 | + |
| 1263 | + ResultSet rset = con.createStatement() |
| 1264 | + .executeQuery("show variables where variable_name='character_set_client' or variable_name='character_set_connection'" |
| 1265 | + + " or variable_name='character_set_results' or variable_name='character_set_server' or variable_name='collation_server'" |
| 1266 | + + " or variable_name='collation_connection'"); |
| 1267 | + while (rset.next()) { |
| 1268 | + System.out.println(rset.getString(1) + "=" + rset.getString(2)); |
| 1269 | + assertEquals(exp.get(rset.getString(1)), rset.getString(2), rset.getString(1)); |
| 1270 | + } |
| 1271 | + |
| 1272 | + con.close(); |
| 1273 | + } |
| 1274 | + |
| 1275 | + public static class Bug95139QueryInterceptor extends BaseQueryInterceptor { |
| 1276 | + int queryVarsCnt = 0; |
| 1277 | + int setNamesCnt = 0; |
| 1278 | + String setNamesQuery = null; |
| 1279 | + int setCharacterSetResultsCnt = 0; |
| 1280 | + String setCharacterSetResultsQuery = null; |
| 1281 | + |
| 1282 | + @Override |
| 1283 | + public <M extends Message> M preProcess(M queryPacket) { |
| 1284 | + String sql = StringUtils.toString(queryPacket.getByteBuffer(), 0, queryPacket.getPosition()); |
| 1285 | + if (sql.contains("SET NAMES")) { |
| 1286 | + this.setNamesCnt++; |
| 1287 | + this.setNamesQuery = sql.substring(sql.indexOf("SET")); |
| 1288 | + } else if (sql.contains("SET " + CharsetSettings.CHARACTER_SET_RESULTS)) { |
| 1289 | + this.setCharacterSetResultsCnt++; |
| 1290 | + this.setCharacterSetResultsQuery = sql.substring(sql.indexOf("SET")); |
| 1291 | + } else if (sql.contains("SHOW VARIABLES") || sql.contains("SELECT @@")) { |
| 1292 | + System.out.println(sql.substring(sql.indexOf("S"))); |
| 1293 | + this.queryVarsCnt++; |
| 1294 | + } |
| 1295 | + return null; |
| 1296 | + } |
| 1297 | + |
| 1298 | + @Override |
| 1299 | + public <T extends Resultset> T preProcess(Supplier<String> str, Query interceptedQuery) { |
| 1300 | + String sql = str.get(); |
| 1301 | + if (sql.contains("SET NAMES")) { |
| 1302 | + this.setNamesCnt++; |
| 1303 | + } else if (sql.contains("SET " + CharsetSettings.CHARACTER_SET_RESULTS)) { |
| 1304 | + this.setCharacterSetResultsCnt++; |
| 1305 | + } else if (sql.contains("SHOW VARIABLES") || sql.contains("SELECT @@")) { |
| 1306 | + System.out.println(sql.substring(sql.indexOf("S"))); |
| 1307 | + this.queryVarsCnt++; |
| 1308 | + } |
| 1309 | + return null; |
| 1310 | + } |
| 1311 | + } |
| 1312 | + |
1186 | 1313 | }
|
0 commit comments