1 | /* |
2 | Copyright (C) 2002-2004 MySQL AB |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of version 2 of the GNU General Public License as |
6 | published by the Free Software Foundation. |
7 | |
8 | There are special exceptions to the terms and conditions of the GPL |
9 | as it is applied to this software. View the full text of the |
10 | exception in file EXCEPTIONS-CONNECTOR-J in the directory of this |
11 | software distribution. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | |
22 | |
23 | |
24 | */ |
25 | package com.mysql.jdbc; |
26 | |
27 | import java.sql.SQLException; |
28 | import java.util.ArrayList; |
29 | import java.util.Collections; |
30 | import java.util.HashMap; |
31 | import java.util.Iterator; |
32 | import java.util.List; |
33 | import java.util.Locale; |
34 | import java.util.Map; |
35 | import java.util.Properties; |
36 | import java.util.Set; |
37 | import java.util.SortedSet; |
38 | |
39 | /** |
40 | * Mapping between MySQL charset names and Java charset names. I've investigated |
41 | * placing these in a .properties file, but unfortunately under most appservers |
42 | * this complicates configuration because the security policy needs to be |
43 | * changed by the user to allow the driver to read them :( |
44 | * |
45 | * @author Mark Matthews |
46 | */ |
47 | public class CharsetMapping { |
48 | private static final Properties CHARSET_CONFIG = new Properties(); |
49 | |
50 | /** |
51 | * Map of MySQL-4.1 charset indexes to Java encoding names |
52 | */ |
53 | public static final String[] INDEX_TO_CHARSET; |
54 | |
55 | /** Mapping of Java charset names to MySQL charset names */ |
56 | private static final Map JAVA_TO_MYSQL_CHARSET_MAP; |
57 | |
58 | private static final Map JAVA_UC_TO_MYSQL_CHARSET_MAP; |
59 | |
60 | private static final Map ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP; |
61 | |
62 | /** Map/List of multibyte character sets (using MySQL names) */ |
63 | private static final Map MULTIBYTE_CHARSETS; |
64 | |
65 | private static final Map MYSQL_TO_JAVA_CHARSET_MAP; |
66 | |
67 | static { |
68 | |
69 | CHARSET_CONFIG.setProperty("javaToMysqlMappings", |
70 | // |
71 | // Note: This used to be stored in Charsets.properties, |
72 | // but turned out to be problematic when dealing with |
73 | // Tomcat classloaders when the security manager was |
74 | // enabled |
75 | // |
76 | // Java Encoding MySQL Name (and version, '*' |
77 | // denotes preferred value) |
78 | // |
79 | "US-ASCII = usa7," |
80 | + "US-ASCII = ascii," |
81 | + "Big5 = big5," |
82 | + "GBK = gbk," |
83 | + "SJIS = sjis," |
84 | + "EUC_CN = gb2312," |
85 | + "EUC_JP = ujis," |
86 | + "EUC_JP_Solaris = >5.0.3 eucjpms," |
87 | + "EUC_KR = euc_kr," |
88 | + "EUC_KR = >4.1.0 euckr," |
89 | + "ISO8859_1 = *latin1," |
90 | + "ISO8859_1 = latin1_de," |
91 | + "ISO8859_1 = german1," |
92 | + "ISO8859_1 = danish," |
93 | + "ISO8859_2 = latin2," |
94 | + "ISO8859_2 = czech," |
95 | + "ISO8859_2 = hungarian," |
96 | + "ISO8859_2 = croat," |
97 | + "ISO8859_7 = greek," |
98 | + "ISO8859_7 = latin7," |
99 | + "ISO8859_8 = hebrew," |
100 | + "ISO8859_9 = latin5," |
101 | + "ISO8859_13 = latvian," |
102 | + "ISO8859_13 = latvian1," |
103 | + "ISO8859_13 = estonia," |
104 | + "Cp437 = *>4.1.0 cp850," |
105 | + "Cp437 = dos," |
106 | + "Cp850 = Cp850," |
107 | + "Cp852 = Cp852," |
108 | + "Cp866 = cp866," |
109 | + "KOI8_R = koi8_ru," |
110 | + "KOI8_R = >4.1.0 koi8r," |
111 | + "TIS620 = tis620," |
112 | + "Cp1250 = cp1250," |
113 | + "Cp1250 = win1250," |
114 | + "Cp1251 = *>4.1.0 cp1251," |
115 | + "Cp1251 = win1251," |
116 | + "Cp1251 = cp1251cias," |
117 | + "Cp1251 = cp1251csas," |
118 | + "Cp1256 = cp1256," |
119 | + "Cp1251 = win1251ukr," |
120 | + "Cp1252 = latin1," |
121 | + "Cp1257 = cp1257," |
122 | + "MacRoman = macroman," |
123 | + "MacCentralEurope = macce," |
124 | + "UTF-8 = utf8," |
125 | + "UnicodeBig = ucs2," |
126 | + "US-ASCII = binary," |
127 | + "Cp943 = sjis," |
128 | + "MS932 = sjis," |
129 | + "MS932 = >4.1.11 cp932," |
130 | + "WINDOWS-31J = sjis," |
131 | + "WINDOWS-31J = >4.1.11 cp932," |
132 | + "CP932 = sjis," |
133 | + "CP932 = *>4.1.11 cp932," |
134 | + "SHIFT_JIS = sjis," |
135 | + "ASCII = ascii," |
136 | + "LATIN5 = latin5," |
137 | + "LATIN7 = latin7," |
138 | + "HEBREW = hebrew," |
139 | + "GREEK = greek," |
140 | + "EUCKR = euckr," |
141 | + "GB2312 = gb2312," |
142 | + "LATIN2 = latin2"); |
143 | |
144 | HashMap javaToMysqlMap = new HashMap(); |
145 | |
146 | populateMapWithKeyValuePairs("javaToMysqlMappings", javaToMysqlMap, |
147 | true, false); |
148 | JAVA_TO_MYSQL_CHARSET_MAP = Collections.unmodifiableMap(javaToMysqlMap); |
149 | |
150 | HashMap mysqlToJavaMap = new HashMap(); |
151 | |
152 | Set keySet = JAVA_TO_MYSQL_CHARSET_MAP.keySet(); |
153 | |
154 | Iterator javaCharsets = keySet.iterator(); |
155 | |
156 | while (javaCharsets.hasNext()) { |
157 | Object javaEncodingName = javaCharsets.next(); |
158 | List mysqlEncodingList = (List) JAVA_TO_MYSQL_CHARSET_MAP |
159 | .get(javaEncodingName); |
160 | |
161 | Iterator mysqlEncodings = mysqlEncodingList.iterator(); |
162 | |
163 | String mysqlEncodingName = null; |
164 | |
165 | while (mysqlEncodings.hasNext()) { |
166 | VersionedStringProperty mysqlProp = (VersionedStringProperty) mysqlEncodings |
167 | .next(); |
168 | mysqlEncodingName = mysqlProp.toString(); |
169 | |
170 | mysqlToJavaMap.put(mysqlEncodingName, javaEncodingName); |
171 | mysqlToJavaMap.put(mysqlEncodingName |
172 | .toUpperCase(Locale.ENGLISH), javaEncodingName); |
173 | } |
174 | } |
175 | |
176 | // we don't want CP932 to map to CP932 |
177 | mysqlToJavaMap.put("cp932", "Windows-31J"); |
178 | mysqlToJavaMap.put("CP932", "Windows-31J"); |
179 | |
180 | MYSQL_TO_JAVA_CHARSET_MAP = Collections.unmodifiableMap(mysqlToJavaMap); |
181 | |
182 | HashMap ucMap = new HashMap(JAVA_TO_MYSQL_CHARSET_MAP.size()); |
183 | |
184 | Iterator javaNamesKeys = JAVA_TO_MYSQL_CHARSET_MAP.keySet().iterator(); |
185 | |
186 | while (javaNamesKeys.hasNext()) { |
187 | String key = (String) javaNamesKeys.next(); |
188 | |
189 | ucMap.put(key.toUpperCase(Locale.ENGLISH), |
190 | JAVA_TO_MYSQL_CHARSET_MAP.get(key)); |
191 | } |
192 | |
193 | JAVA_UC_TO_MYSQL_CHARSET_MAP = Collections.unmodifiableMap(ucMap); |
194 | |
195 | // |
196 | // Character sets that we can't convert |
197 | // ourselves. |
198 | // |
199 | HashMap tempMapMulti = new HashMap(); |
200 | |
201 | CHARSET_CONFIG.setProperty("multibyteCharsets", |
202 | // |
203 | // Note: This used to be stored in Charsets.properties, |
204 | // but turned out to be problematic when dealing with |
205 | // Tomcat classloaders when the security manager was |
206 | // enabled |
207 | // |
208 | // Java Name MySQL Name (not currently used) |
209 | // |
210 | |
211 | "Big5 = big5," |
212 | + "GBK = gbk," |
213 | + "SJIS = sjis," |
214 | + "EUC_CN = gb2312," |
215 | + "EUC_JP = ujis," |
216 | + "EUC_JP_Solaris = eucjpms," |
217 | + "EUC_KR = euc_kr," |
218 | + "EUC_KR = >4.1.0 euckr," |
219 | + "Cp943 = sjis," |
220 | + "Cp943 = cp943," |
221 | + "WINDOWS-31J = sjis," |
222 | + "WINDOWS-31J = cp932," |
223 | + "CP932 = cp932," |
224 | + "MS932 = sjis," |
225 | + "MS932 = cp932," |
226 | + "SHIFT_JIS = sjis," |
227 | + "EUCKR = euckr," |
228 | + "GB2312 = gb2312," |
229 | + "UTF-8 = utf8," |
230 | + "utf8 = utf8," |
231 | + "UnicodeBig = ucs2"); |
232 | |
233 | populateMapWithKeyValuePairs("multibyteCharsets", tempMapMulti, false, |
234 | true); |
235 | |
236 | MULTIBYTE_CHARSETS = Collections.unmodifiableMap(tempMapMulti); |
237 | |
238 | INDEX_TO_CHARSET = new String[99]; |
239 | |
240 | try { |
241 | INDEX_TO_CHARSET[1] = getJavaEncodingForMysqlEncoding("big5", null); |
242 | INDEX_TO_CHARSET[2] = getJavaEncodingForMysqlEncoding("czech", null); |
243 | INDEX_TO_CHARSET[3] = getJavaEncodingForMysqlEncoding("dec8", null); |
244 | INDEX_TO_CHARSET[4] = getJavaEncodingForMysqlEncoding("dos", null); |
245 | INDEX_TO_CHARSET[5] = getJavaEncodingForMysqlEncoding("german1", |
246 | null); |
247 | INDEX_TO_CHARSET[6] = getJavaEncodingForMysqlEncoding("hp8", null); |
248 | INDEX_TO_CHARSET[7] = getJavaEncodingForMysqlEncoding("koi8_ru", |
249 | null); |
250 | INDEX_TO_CHARSET[8] = getJavaEncodingForMysqlEncoding("latin1", |
251 | null); |
252 | INDEX_TO_CHARSET[9] = getJavaEncodingForMysqlEncoding("latin2", |
253 | null); |
254 | INDEX_TO_CHARSET[10] = getJavaEncodingForMysqlEncoding("swe7", null); |
255 | INDEX_TO_CHARSET[11] = getJavaEncodingForMysqlEncoding("usa7", null); |
256 | INDEX_TO_CHARSET[12] = getJavaEncodingForMysqlEncoding("ujis", null); |
257 | INDEX_TO_CHARSET[13] = getJavaEncodingForMysqlEncoding("sjis", null); |
258 | INDEX_TO_CHARSET[14] = getJavaEncodingForMysqlEncoding("cp1251", |
259 | null); |
260 | INDEX_TO_CHARSET[15] = getJavaEncodingForMysqlEncoding("danish", |
261 | null); |
262 | INDEX_TO_CHARSET[16] = getJavaEncodingForMysqlEncoding("hebrew", |
263 | null); |
264 | INDEX_TO_CHARSET[18] = getJavaEncodingForMysqlEncoding("tis620", |
265 | null); |
266 | INDEX_TO_CHARSET[19] = getJavaEncodingForMysqlEncoding("euc_kr", |
267 | null); |
268 | INDEX_TO_CHARSET[20] = getJavaEncodingForMysqlEncoding("estonia", |
269 | null); |
270 | INDEX_TO_CHARSET[21] = getJavaEncodingForMysqlEncoding("hungarian", |
271 | null); |
272 | INDEX_TO_CHARSET[22] = getJavaEncodingForMysqlEncoding("koi8_ukr", |
273 | null); |
274 | INDEX_TO_CHARSET[23] = getJavaEncodingForMysqlEncoding( |
275 | "win1251ukr", null); |
276 | INDEX_TO_CHARSET[24] = getJavaEncodingForMysqlEncoding("gb2312", |
277 | null); |
278 | INDEX_TO_CHARSET[25] = getJavaEncodingForMysqlEncoding("greek", |
279 | null); |
280 | INDEX_TO_CHARSET[26] = getJavaEncodingForMysqlEncoding("win1250", |
281 | null); |
282 | INDEX_TO_CHARSET[27] = getJavaEncodingForMysqlEncoding("croat", |
283 | null); |
284 | INDEX_TO_CHARSET[28] = getJavaEncodingForMysqlEncoding("gbk", null); |
285 | INDEX_TO_CHARSET[29] = getJavaEncodingForMysqlEncoding("cp1257", |
286 | null); |
287 | INDEX_TO_CHARSET[30] = getJavaEncodingForMysqlEncoding("latin5", |
288 | null); |
289 | INDEX_TO_CHARSET[31] = getJavaEncodingForMysqlEncoding("latin1_de", |
290 | null); |
291 | INDEX_TO_CHARSET[32] = getJavaEncodingForMysqlEncoding("armscii8", |
292 | null); |
293 | INDEX_TO_CHARSET[33] = getJavaEncodingForMysqlEncoding("utf8", null); |
294 | INDEX_TO_CHARSET[34] = getJavaEncodingForMysqlEncoding("win1250ch", |
295 | null); |
296 | INDEX_TO_CHARSET[35] = getJavaEncodingForMysqlEncoding("ucs2", null); |
297 | INDEX_TO_CHARSET[36] = getJavaEncodingForMysqlEncoding("cp866", |
298 | null); |
299 | INDEX_TO_CHARSET[37] = getJavaEncodingForMysqlEncoding("keybcs2", |
300 | null); |
301 | INDEX_TO_CHARSET[38] = getJavaEncodingForMysqlEncoding("macce", |
302 | null); |
303 | INDEX_TO_CHARSET[39] = getJavaEncodingForMysqlEncoding("macroman", |
304 | null); |
305 | INDEX_TO_CHARSET[40] = getJavaEncodingForMysqlEncoding("pclatin2", |
306 | null); |
307 | INDEX_TO_CHARSET[41] = getJavaEncodingForMysqlEncoding("latvian", |
308 | null); |
309 | INDEX_TO_CHARSET[42] = getJavaEncodingForMysqlEncoding("latvian1", |
310 | null); |
311 | INDEX_TO_CHARSET[43] = getJavaEncodingForMysqlEncoding("maccebin", |
312 | null); |
313 | INDEX_TO_CHARSET[44] = getJavaEncodingForMysqlEncoding("macceciai", |
314 | null); |
315 | INDEX_TO_CHARSET[45] = getJavaEncodingForMysqlEncoding("maccecias", |
316 | null); |
317 | INDEX_TO_CHARSET[46] = getJavaEncodingForMysqlEncoding("maccecsas", |
318 | null); |
319 | INDEX_TO_CHARSET[47] = getJavaEncodingForMysqlEncoding("latin1bin", |
320 | null); |
321 | INDEX_TO_CHARSET[48] = getJavaEncodingForMysqlEncoding( |
322 | "latin1cias", null); |
323 | INDEX_TO_CHARSET[49] = getJavaEncodingForMysqlEncoding( |
324 | "latin1csas", null); |
325 | INDEX_TO_CHARSET[50] = getJavaEncodingForMysqlEncoding("cp1251bin", |
326 | null); |
327 | INDEX_TO_CHARSET[51] = getJavaEncodingForMysqlEncoding( |
328 | "cp1251cias", null); |
329 | INDEX_TO_CHARSET[52] = getJavaEncodingForMysqlEncoding( |
330 | "cp1251csas", null); |
331 | INDEX_TO_CHARSET[53] = getJavaEncodingForMysqlEncoding( |
332 | "macromanbin", null); |
333 | INDEX_TO_CHARSET[54] = getJavaEncodingForMysqlEncoding( |
334 | "macromancias", null); |
335 | INDEX_TO_CHARSET[55] = getJavaEncodingForMysqlEncoding( |
336 | "macromanciai", null); |
337 | INDEX_TO_CHARSET[56] = getJavaEncodingForMysqlEncoding( |
338 | "macromancsas", null); |
339 | INDEX_TO_CHARSET[57] = getJavaEncodingForMysqlEncoding("cp1256", |
340 | null); |
341 | INDEX_TO_CHARSET[63] = getJavaEncodingForMysqlEncoding("binary", |
342 | null); |
343 | INDEX_TO_CHARSET[64] = getJavaEncodingForMysqlEncoding("armscii", |
344 | null); |
345 | INDEX_TO_CHARSET[65] = getJavaEncodingForMysqlEncoding("ascii", |
346 | null); |
347 | INDEX_TO_CHARSET[66] = getJavaEncodingForMysqlEncoding("cp1250", |
348 | null); |
349 | INDEX_TO_CHARSET[67] = getJavaEncodingForMysqlEncoding("cp1256", |
350 | null); |
351 | INDEX_TO_CHARSET[68] = getJavaEncodingForMysqlEncoding("cp866", |
352 | null); |
353 | INDEX_TO_CHARSET[69] = getJavaEncodingForMysqlEncoding("dec8", null); |
354 | INDEX_TO_CHARSET[70] = getJavaEncodingForMysqlEncoding("greek", |
355 | null); |
356 | INDEX_TO_CHARSET[71] = getJavaEncodingForMysqlEncoding("hebrew", |
357 | null); |
358 | INDEX_TO_CHARSET[72] = getJavaEncodingForMysqlEncoding("hp8", null); |
359 | INDEX_TO_CHARSET[73] = getJavaEncodingForMysqlEncoding("keybcs2", |
360 | null); |
361 | INDEX_TO_CHARSET[74] = getJavaEncodingForMysqlEncoding("koi8r", |
362 | null); |
363 | INDEX_TO_CHARSET[75] = getJavaEncodingForMysqlEncoding("koi8ukr", |
364 | null); |
365 | INDEX_TO_CHARSET[77] = getJavaEncodingForMysqlEncoding("latin2", |
366 | null); |
367 | INDEX_TO_CHARSET[78] = getJavaEncodingForMysqlEncoding("latin5", |
368 | null); |
369 | INDEX_TO_CHARSET[79] = getJavaEncodingForMysqlEncoding("latin7", |
370 | null); |
371 | INDEX_TO_CHARSET[80] = getJavaEncodingForMysqlEncoding("cp850", |
372 | null); |
373 | INDEX_TO_CHARSET[81] = getJavaEncodingForMysqlEncoding("cp852", |
374 | null); |
375 | INDEX_TO_CHARSET[82] = getJavaEncodingForMysqlEncoding("swe7", null); |
376 | INDEX_TO_CHARSET[83] = getJavaEncodingForMysqlEncoding("utf8", null); |
377 | INDEX_TO_CHARSET[84] = getJavaEncodingForMysqlEncoding("big5", null); |
378 | INDEX_TO_CHARSET[85] = getJavaEncodingForMysqlEncoding("euckr", |
379 | null); |
380 | INDEX_TO_CHARSET[86] = getJavaEncodingForMysqlEncoding("gb2312", |
381 | null); |
382 | INDEX_TO_CHARSET[87] = getJavaEncodingForMysqlEncoding("gbk", null); |
383 | INDEX_TO_CHARSET[88] = getJavaEncodingForMysqlEncoding("sjis", null); |
384 | INDEX_TO_CHARSET[89] = getJavaEncodingForMysqlEncoding("tis620", |
385 | null); |
386 | INDEX_TO_CHARSET[90] = getJavaEncodingForMysqlEncoding("ucs2", null); |
387 | INDEX_TO_CHARSET[91] = getJavaEncodingForMysqlEncoding("ujis", null); |
388 | INDEX_TO_CHARSET[92] = getJavaEncodingForMysqlEncoding("geostd8", |
389 | null); |
390 | INDEX_TO_CHARSET[93] = getJavaEncodingForMysqlEncoding("geostd8", |
391 | null); |
392 | INDEX_TO_CHARSET[94] = getJavaEncodingForMysqlEncoding("latin1", |
393 | null); |
394 | INDEX_TO_CHARSET[95] = getJavaEncodingForMysqlEncoding("cp932", |
395 | null); |
396 | INDEX_TO_CHARSET[96] = getJavaEncodingForMysqlEncoding("cp932", |
397 | null); |
398 | INDEX_TO_CHARSET[97] = getJavaEncodingForMysqlEncoding("eucjpms", |
399 | null); |
400 | INDEX_TO_CHARSET[98] = getJavaEncodingForMysqlEncoding("eucjpms", |
401 | null); |
402 | } catch (SQLException sqlEx) { |
403 | // ignore, it won't happen in this case |
404 | } |
405 | |
406 | Map tempMap = new HashMap(); |
407 | |
408 | tempMap.put("czech", "latin2"); |
409 | tempMap.put("danish", "latin1"); |
410 | tempMap.put("dutch", "latin1"); |
411 | tempMap.put("english", "latin1"); |
412 | tempMap.put("estonian", "latin7"); |
413 | tempMap.put("french", "latin1"); |
414 | tempMap.put("german", "latin1"); |
415 | tempMap.put("greek", "greek"); |
416 | tempMap.put("hungarian", "latin2"); |
417 | tempMap.put("italian", "latin1"); |
418 | tempMap.put("japanese", "ujis"); |
419 | tempMap.put("japanese-sjis", "sjis"); |
420 | tempMap.put("korean", "euckr"); |
421 | tempMap.put("norwegian", "latin1"); |
422 | tempMap.put("norwegian-ny", "latin1"); |
423 | tempMap.put("polish", "latin2"); |
424 | tempMap.put("portuguese", "latin1"); |
425 | tempMap.put("romanian", "latin2"); |
426 | tempMap.put("russian", "koi8r"); |
427 | tempMap.put("serbian", "cp1250"); |
428 | tempMap.put("slovak", "latin2"); |
429 | tempMap.put("spanish", "latin1"); |
430 | tempMap.put("swedish", "latin1"); |
431 | tempMap.put("ukrainian", "koi8u"); |
432 | |
433 | ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP = |
434 | Collections.unmodifiableMap(tempMap); |
435 | } |
436 | |
437 | final static String getJavaEncodingForMysqlEncoding(String mysqlEncoding, |
438 | Connection conn) throws SQLException { |
439 | |
440 | if (conn != null && conn.versionMeetsMinimum(4, 1, 0) && |
441 | "latin1".equalsIgnoreCase(mysqlEncoding)) { |
442 | return "Cp1252"; |
443 | } |
444 | |
445 | return (String) MYSQL_TO_JAVA_CHARSET_MAP.get(mysqlEncoding); |
446 | } |
447 | |
448 | final static String getMysqlEncodingForJavaEncoding(String javaEncodingUC, |
449 | Connection conn) throws SQLException { |
450 | List mysqlEncodings = (List) CharsetMapping.JAVA_UC_TO_MYSQL_CHARSET_MAP |
451 | .get(javaEncodingUC); |
452 | ; |
453 | |
454 | if (mysqlEncodings != null) { |
455 | Iterator iter = mysqlEncodings.iterator(); |
456 | |
457 | VersionedStringProperty versionedProp = null; |
458 | |
459 | while (iter.hasNext()) { |
460 | VersionedStringProperty propToCheck = (VersionedStringProperty) iter |
461 | .next(); |
462 | |
463 | if (conn == null) { |
464 | // Take the first one we get |
465 | |
466 | return propToCheck.toString(); |
467 | } |
468 | |
469 | if (versionedProp != null && !versionedProp.preferredValue) { |
470 | if (versionedProp.majorVersion == propToCheck.majorVersion |
471 | && versionedProp.minorVersion == propToCheck.minorVersion |
472 | && versionedProp.subminorVersion == propToCheck.subminorVersion) { |
473 | return versionedProp.toString(); |
474 | } |
475 | } |
476 | |
477 | if (propToCheck.isOkayForVersion(conn)) { |
478 | if (propToCheck.preferredValue) { |
479 | return propToCheck.toString(); |
480 | } |
481 | |
482 | versionedProp = propToCheck; |
483 | } else { |
484 | break; |
485 | } |
486 | } |
487 | |
488 | if (versionedProp != null) { |
489 | return versionedProp.toString(); |
490 | } |
491 | } |
492 | |
493 | return null; |
494 | } |
495 | |
496 | final static int getNumberOfCharsetsConfigured() { |
497 | return MYSQL_TO_JAVA_CHARSET_MAP.size() / 2; // because we UC every |
498 | // key |
499 | } |
500 | |
501 | /** |
502 | * Returns the character encoding for error messages returned from the |
503 | * server. Doesn't return useful values other than Cp1252 until the driver |
504 | * has gone through initialization phase and determined server configuration, |
505 | * as not enough information is available to make an intelligent decision |
506 | * until then. |
507 | * |
508 | * @param conn the connection to the MySQL server |
509 | * @return the Java encoding name that error messages use |
510 | * @throws SQLException if determination of the character encoding fails |
511 | */ |
512 | final static String getCharacterEncodingForErrorMessages(Connection conn) throws SQLException { |
513 | String errorMessageFile = conn.getServerVariable("language"); |
514 | |
515 | if (errorMessageFile == null || errorMessageFile.length() == 0) { |
516 | // punt |
517 | return "Cp1252"; |
518 | } |
519 | |
520 | int endWithoutSlash = errorMessageFile.length(); |
521 | |
522 | if (errorMessageFile.endsWith("/") || errorMessageFile.endsWith("\\")) { |
523 | endWithoutSlash--; |
524 | } |
525 | |
526 | int lastSlashIndex = errorMessageFile.lastIndexOf('/', endWithoutSlash - 1); |
527 | |
528 | if (lastSlashIndex == -1) { |
529 | lastSlashIndex = errorMessageFile.lastIndexOf('\\', endWithoutSlash - 1); |
530 | } |
531 | |
532 | if (lastSlashIndex == -1) { |
533 | lastSlashIndex = 0; |
534 | } |
535 | |
536 | if (lastSlashIndex == endWithoutSlash || endWithoutSlash < lastSlashIndex) { |
537 | // punt |
538 | return "Cp1252"; |
539 | } |
540 | |
541 | errorMessageFile = errorMessageFile.substring(lastSlashIndex + 1, endWithoutSlash); |
542 | |
543 | String errorMessageEncodingMysql = (String)ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP.get(errorMessageFile); |
544 | |
545 | if (errorMessageEncodingMysql == null) { |
546 | // punt |
547 | return "Cp1252"; |
548 | } |
549 | |
550 | String javaEncoding = getJavaEncodingForMysqlEncoding(errorMessageEncodingMysql, conn); |
551 | |
552 | if (javaEncoding == null) { |
553 | // punt |
554 | return "Cp1252"; |
555 | } |
556 | |
557 | return javaEncoding; |
558 | } |
559 | |
560 | final static boolean isAliasForSjis(String encoding) { |
561 | return ("SJIS".equalsIgnoreCase(encoding) |
562 | || "WINDOWS-31J".equalsIgnoreCase(encoding) |
563 | || "MS932".equalsIgnoreCase(encoding) |
564 | || "SHIFT_JIS".equalsIgnoreCase(encoding) || "CP943" |
565 | .equalsIgnoreCase(encoding)); |
566 | |
567 | } |
568 | |
569 | final static boolean isMultibyteCharset(String javaEncodingName) { |
570 | String javaEncodingNameUC = javaEncodingName |
571 | .toUpperCase(Locale.ENGLISH); |
572 | |
573 | return MULTIBYTE_CHARSETS.containsKey(javaEncodingNameUC); |
574 | } |
575 | |
576 | private static void populateMapWithKeyValuePairs(String configKey, |
577 | Map mapToPopulate, boolean addVersionedProperties, |
578 | boolean addUppercaseKeys) { |
579 | String javaToMysqlConfig = CHARSET_CONFIG.getProperty(configKey); |
580 | |
581 | if (javaToMysqlConfig != null) { |
582 | List mappings = StringUtils.split(javaToMysqlConfig, ",", true); |
583 | |
584 | if (mappings != null) { |
585 | Iterator mappingsIter = mappings.iterator(); |
586 | |
587 | while (mappingsIter.hasNext()) { |
588 | String aMapping = (String) mappingsIter.next(); |
589 | |
590 | List parsedPair = StringUtils.split(aMapping, "=", true); |
591 | |
592 | if (parsedPair.size() == 2) { |
593 | String key = parsedPair.get(0).toString(); |
594 | String value = parsedPair.get(1).toString(); |
595 | |
596 | if (addVersionedProperties) { |
597 | List versionedProperties = (List) mapToPopulate |
598 | .get(key); |
599 | |
600 | if (versionedProperties == null) { |
601 | versionedProperties = new ArrayList(); |
602 | mapToPopulate.put(key, versionedProperties); |
603 | } |
604 | |
605 | VersionedStringProperty verProp = new VersionedStringProperty( |
606 | value); |
607 | versionedProperties.add(verProp); |
608 | |
609 | if (addUppercaseKeys) { |
610 | String keyUc = key.toUpperCase(Locale.ENGLISH); |
611 | |
612 | versionedProperties = (List) mapToPopulate |
613 | .get(keyUc); |
614 | |
615 | if (versionedProperties == null) { |
616 | versionedProperties = new ArrayList(); |
617 | mapToPopulate.put(keyUc, |
618 | versionedProperties); |
619 | } |
620 | |
621 | versionedProperties.add(verProp); |
622 | } |
623 | } else { |
624 | mapToPopulate.put(key, value); |
625 | |
626 | if (addUppercaseKeys) { |
627 | mapToPopulate.put(key |
628 | .toUpperCase(Locale.ENGLISH), value); |
629 | } |
630 | } |
631 | } else { |
632 | throw new RuntimeException( |
633 | "Syntax error in Charsets.properties " |
634 | + "resource for token \"" + aMapping |
635 | + "\"."); |
636 | } |
637 | } |
638 | } else { |
639 | throw new RuntimeException("Missing/corrupt entry for \"" |
640 | + configKey + "\" in Charsets.properties."); |
641 | } |
642 | } else { |
643 | throw new RuntimeException("Could not find configuration value " |
644 | + "\"" + configKey + "\" in Charsets.properties resource"); |
645 | } |
646 | } |
647 | } |
648 | |
649 | class VersionedStringProperty { |
650 | int majorVersion, minorVersion, subminorVersion; |
651 | |
652 | boolean preferredValue = false; |
653 | |
654 | String propertyInfo; |
655 | |
656 | VersionedStringProperty(String property) { |
657 | property = property.trim(); |
658 | |
659 | if (property.startsWith("*")) { |
660 | property = property.substring(1); |
661 | preferredValue = true; |
662 | } |
663 | |
664 | if (property.startsWith(">")) { |
665 | property = property.substring(1); |
666 | |
667 | int charPos = 0; |
668 | |
669 | for (charPos = 0; charPos < property.length(); charPos++) { |
670 | char c = property.charAt(charPos); |
671 | |
672 | if (!Character.isWhitespace(c) && !Character.isDigit(c) |
673 | && c != '.') { |
674 | break; |
675 | } |
676 | } |
677 | |
678 | String versionInfo = property.substring(0, charPos); |
679 | List versionParts = StringUtils.split(versionInfo, ".", true); |
680 | |
681 | majorVersion = Integer.parseInt(versionParts.get(0).toString()); |
682 | |
683 | if (versionParts.size() > 1) { |
684 | minorVersion = Integer.parseInt(versionParts.get(1).toString()); |
685 | } else { |
686 | minorVersion = 0; |
687 | } |
688 | |
689 | if (versionParts.size() > 2) { |
690 | subminorVersion = Integer.parseInt(versionParts.get(2) |
691 | .toString()); |
692 | } else { |
693 | subminorVersion = 0; |
694 | } |
695 | |
696 | propertyInfo = property.substring(charPos); |
697 | } else { |
698 | majorVersion = minorVersion = subminorVersion = 0; |
699 | propertyInfo = property; |
700 | } |
701 | } |
702 | |
703 | VersionedStringProperty(String property, int major, int minor, int subminor) { |
704 | propertyInfo = property; |
705 | majorVersion = major; |
706 | minorVersion = minor; |
707 | subminorVersion = subminor; |
708 | } |
709 | |
710 | boolean isOkayForVersion(Connection conn) throws SQLException { |
711 | return conn.versionMeetsMinimum(majorVersion, minorVersion, |
712 | subminorVersion); |
713 | } |
714 | |
715 | public String toString() { |
716 | return propertyInfo; |
717 | } |
718 | } |