List:Commits« Previous MessageNext Message »
From:mmatthews Date:June 16 2006 7:12pm
Subject:Connector/J commit: r5397 - in branches: branch_5_0/connector-j branch_5_0/connector-j/src/com/mysql/jdbc branch_5_1/connector-j branch_5_1/connector-...
View as plain text  
Modified:
   branches/branch_5_0/connector-j/CHANGES
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/CharsetMapping.java
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java
   branches/branch_5_1/connector-j/CHANGES
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/Buffer.java
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/CharsetMapping.java
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/Connection.java
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java
Log:
Fixed BUG#18086 - Driver fails on non-ASCII platforms. The driver
      was assuming that the platform character set would be a superset 
      of MySQL's "latin1" when doing the handshake for authentication,
      and when reading error messages. We now use Cp1252 for all strings
      sent to the server during the handshake phase, and a hard-coded mapping
      of the "language" server variable to the character set that 
      is used for error messages.

Modified: branches/branch_5_0/connector-j/CHANGES
===================================================================
--- branches/branch_5_0/connector-j/CHANGES	2006-06-16 00:01:41 UTC (rev 5396)
+++ branches/branch_5_0/connector-j/CHANGES	2006-06-16 17:12:26 UTC (rev 5397)
@@ -6,6 +6,14 @@
     - Fixed BUG#17401 - Can't use XAConnection for local transactions when
       no global transaction is in progress.
       
+    - Fixed BUG#18086 - Driver fails on non-ASCII platforms. The driver
+      was assuming that the platform character set would be a superset 
+      of MySQL's "latin1" when doing the handshake for authentication,
+      and when reading error messages. We now use Cp1252 for all strings
+      sent to the server during the handshake phase, and a hard-coded mapping
+      of the "language" server variable to the character set that 
+      is used for error messages.
+      
 12-23-05 - Version 5.0.0-beta
 
     - XADataSource implemented (ported from 3.2 branch which won't be 

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/CharsetMapping.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/CharsetMapping.java	2006-06-16
00:01:41 UTC (rev 5396)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/CharsetMapping.java	2006-06-16
17:12:26 UTC (rev 5397)
@@ -56,6 +56,8 @@
 	private static final Map JAVA_TO_MYSQL_CHARSET_MAP;
 
 	private static final Map JAVA_UC_TO_MYSQL_CHARSET_MAP;
+	
+	private static final Map ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP;
 
 	/** Map/List of multibyte character sets (using MySQL names) */
 	private static final Map MULTIBYTE_CHARSETS;
@@ -400,6 +402,36 @@
 		} catch (SQLException sqlEx) {
 			// ignore, it won't happen in this case
 		}
+		
+		Map tempMap = new HashMap();
+		
+		tempMap.put("czech", "latin2");
+		tempMap.put("danish", "latin1");
+		tempMap.put("dutch", "latin1");
+		tempMap.put("english", "latin1");
+		tempMap.put("estonian", "latin7");
+		tempMap.put("french", "latin1");
+		tempMap.put("german", "latin1");
+		tempMap.put("greek", "greek");
+		tempMap.put("hungarian", "latin2");
+		tempMap.put("italian", "latin1");
+		tempMap.put("japanese", "ujis");
+		tempMap.put("japanese-sjis", "sjis");
+		tempMap.put("korean", "euckr");
+		tempMap.put("norwegian", "latin1");
+		tempMap.put("norwegian-ny", "latin1");
+		tempMap.put("polish", "latin2");
+		tempMap.put("portuguese", "latin1");
+		tempMap.put("romanian", "latin2");
+		tempMap.put("russian", "koi8r");
+		tempMap.put("serbian", "cp1250");
+		tempMap.put("slovak", "latin2");
+		tempMap.put("spanish", "latin1");
+		tempMap.put("swedish", "latin1");
+		tempMap.put("ukrainian", "koi8u");
+		
+		ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP = 
+			Collections.unmodifiableMap(tempMap);
 	}
 
 	final static String getJavaEncodingForMysqlEncoding(String mysqlEncoding,
@@ -407,7 +439,7 @@
 		
 		if (conn != null && conn.versionMeetsMinimum(4, 1, 0) && 
 				"latin1".equalsIgnoreCase(mysqlEncoding)) {
-			return "cp1252";
+			return "Cp1252";
 		}
 		
 		return (String) MYSQL_TO_JAVA_CHARSET_MAP.get(mysqlEncoding);
@@ -466,6 +498,65 @@
 														// key
 	}
 
+	/**
+	 * Returns the character encoding for error messages returned from the
+	 * server. Doesn't return useful values other than Cp1252 until the driver
+	 * has gone through initialization phase and determined server configuration,
+	 * as not enough information is available to make an intelligent decision
+	 * until then.
+	 * 
+	 * @param conn the connection to the MySQL server
+	 * @return the Java encoding name that error messages use
+	 * @throws SQLException if determination of the character encoding fails
+	 */
+	final static String getCharacterEncodingForErrorMessages(Connection conn) throws
SQLException {
+		String errorMessageFile = conn.getServerVariable("language");
+		
+		if (errorMessageFile == null || errorMessageFile.length() == 0) {
+			// punt
+			return "Cp1252";
+		}
+		
+		int endWithoutSlash = errorMessageFile.length();
+		
+		if (errorMessageFile.endsWith("/") || errorMessageFile.endsWith("\\")) {
+			endWithoutSlash--;
+		}
+			
+		int lastSlashIndex = errorMessageFile.lastIndexOf('/', endWithoutSlash - 1);
+		
+		if (lastSlashIndex == -1) {
+			lastSlashIndex = errorMessageFile.lastIndexOf('\\', endWithoutSlash - 1);
+		}
+		
+		if (lastSlashIndex == -1) {
+			lastSlashIndex = 0;
+		}
+		
+		if (lastSlashIndex == endWithoutSlash || endWithoutSlash < lastSlashIndex) {
+			// punt
+			return "Cp1252";
+		}
+		
+		errorMessageFile = errorMessageFile.substring(lastSlashIndex + 1, endWithoutSlash);
+		
+		String errorMessageEncodingMysql =
(String)ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP.get(errorMessageFile);
+		
+		if (errorMessageEncodingMysql == null) {
+			// punt
+			return "Cp1252";
+		}
+		
+		String javaEncoding = getJavaEncodingForMysqlEncoding(errorMessageEncodingMysql, conn);
+		
+		if (javaEncoding == null) {
+			// punt
+			return "Cp1252";
+		}
+		
+		return javaEncoding;
+	}
+	
 	final static boolean isAliasForSjis(String encoding) {
 		return ("SJIS".equalsIgnoreCase(encoding)
 				|| "WINDOWS-31J".equalsIgnoreCase(encoding)

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java	2006-06-16 00:01:41
UTC (rev 5396)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java	2006-06-16 17:12:26
UTC (rev 5397)
@@ -1409,7 +1409,10 @@
 	// we don't want to be able to publicly clone this...
 	
 	private String origDatabaseToConnectTo;
+
+	private String errorMessageEncoding = "Cp1252"; // to begin with, changes after we talk
to the server
 	
+	
 	/**
 	 * Creates a connection to a MySQL Server.
 	 * 
@@ -3939,7 +3942,10 @@
 				}
 			}
 		}
-
+		
+		this.errorMessageEncoding = 
+			CharsetMapping.getCharacterEncodingForErrorMessages(this);
+		
 		boolean overrideDefaultAutocommit = false;
 		
 		String initConnectValue = (String) this.serverVariables
@@ -5619,4 +5625,8 @@
 
 		return this.io.versionMeetsMinimum(major, minor, subminor);
 	}
+
+	protected String getErrorMessageEncoding() {
+		return errorMessageEncoding;
+	}
 }

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java	2006-06-16 00:01:41
UTC (rev 5396)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/MysqlIO.java	2006-06-16 17:12:26
UTC (rev 5397)
@@ -1210,16 +1210,16 @@
                 }
 
                 // User/Password data
-                packet.writeString(user);
+                packet.writeString(user, "Cp1252");
 
                 if (this.protocolVersion > 9) {
-                    packet.writeString(Util.newCrypt(password, this.seed));
+                    packet.writeString(Util.newCrypt(password, this.seed), "Cp1252");
                 } else {
-                    packet.writeString(Util.oldCrypt(password, this.seed));
+                    packet.writeString(Util.oldCrypt(password, this.seed), "Cp1252");
                 }
 
                 if (this.useConnectWithDb) {
-                    packet.writeString(database);
+                    packet.writeString(database, "Cp1252");
                 }
 
                 send(packet, packet.getPosition());
@@ -2818,7 +2818,8 @@
 
                 String xOpen = null;
 
-                serverErrorMessage = resultPacket.readString();
+                serverErrorMessage = 
+                	resultPacket.readString(this.connection.getErrorMessageEncoding());
 
                 if (serverErrorMessage.startsWith("#")) { //$NON-NLS-1$
 
@@ -2868,7 +2869,8 @@
                 }
             }
 
-            serverErrorMessage = resultPacket.readString();
+            serverErrorMessage = resultPacket.readString(
+            		this.connection.getErrorMessageEncoding());
             clearInputStream();
 
             if (serverErrorMessage.indexOf(Messages.getString("MysqlIO.70")) != -1) {
//$NON-NLS-1$
@@ -3073,18 +3075,18 @@
         }
 
         // User/Password data
-        packet.writeString(user);
+        packet.writeString(user, "Cp1252");
 
         if (password.length() != 0) {
             /* Prepare false scramble  */
-            packet.writeString(FALSE_SCRAMBLE);
+            packet.writeString(FALSE_SCRAMBLE, "Cp1252");
         } else {
             /* For empty password*/
-            packet.writeString(""); //$NON-NLS-1$
+            packet.writeString("", "Cp1252"); //$NON-NLS-1$
         }
 
         if (this.useConnectWithDb) {
-            packet.writeString(database);
+            packet.writeString(database, "Cp1252");
         }
 
         send(packet, packet.getPosition());
@@ -3162,7 +3164,7 @@
                                     mysqlScrambleBuff), password);
 
                         Buffer packet2 = new Buffer(packLength);
-                        packet2.writeString(scrambledPassword);
+                        packet2.writeString(scrambledPassword, "Cp1252");
                         this.packetSequence++;
 
                         send(packet2, 24);

Modified: branches/branch_5_1/connector-j/CHANGES
===================================================================
--- branches/branch_5_1/connector-j/CHANGES	2006-06-16 00:01:41 UTC (rev 5396)
+++ branches/branch_5_1/connector-j/CHANGES	2006-06-16 17:12:26 UTC (rev 5397)
@@ -8,6 +8,14 @@
     - Fixed BUG#17401 - Can't use XAConnection for local transactions when
       no global transaction is in progress.
       
+    - Fixed BUG#18086 - Driver fails on non-ASCII platforms. The driver
+      was assuming that the platform character set would be a superset 
+      of MySQL's "latin1" when doing the handshake for authentication,
+      and when reading error messages. We now use Cp1252 for all strings
+      sent to the server during the handshake phase, and a hard-coded mapping
+      of the "language" server variable to the character set that 
+      is used for error messages.
+      
 12-23-05 - Version 5.0.0-beta
 
     - XADataSource implemented (ported from 3.2 branch which won't be 

Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/Buffer.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/Buffer.java	2006-06-16 00:01:41 UTC
(rev 5396)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/Buffer.java	2006-06-16 17:12:26 UTC
(rev 5397)
@@ -621,6 +621,18 @@
 		this.byteBuffer[this.position++] = 0;
 	}
 
+	//	 Write null-terminated string in the given encoding
+	final void writeString(String s, String encoding) throws SQLException {
+		ensureCapacity((s.length() * 2) + 1);
+		try {
+			writeStringNoNull(s, encoding, encoding, false);
+		} catch (UnsupportedEncodingException ue) {
+			throw new SQLException(ue.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
+		}
+		
+		this.byteBuffer[this.position++] = 0;
+	}
+
 	// Write string, with no termination
 	final void writeStringNoNull(String s) throws SQLException {
 		int len = s.length();

Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/CharsetMapping.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/CharsetMapping.java	2006-06-16
00:01:41 UTC (rev 5396)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/CharsetMapping.java	2006-06-16
17:12:26 UTC (rev 5397)
@@ -57,6 +57,8 @@
 
 	private static final Map JAVA_UC_TO_MYSQL_CHARSET_MAP;
 
+	private static final Map ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP;
+
 	/** Map/List of multibyte character sets (using MySQL names) */
 	private static final Map MULTIBYTE_CHARSETS;
 
@@ -400,6 +402,36 @@
 		} catch (SQLException sqlEx) {
 			// ignore, it won't happen in this case
 		}
+		
+		Map tempMap = new HashMap();
+		
+		tempMap.put("czech", "latin2");
+		tempMap.put("danish", "latin1");
+		tempMap.put("dutch", "latin1");
+		tempMap.put("english", "latin1");
+		tempMap.put("estonian", "latin7");
+		tempMap.put("french", "latin1");
+		tempMap.put("german", "latin1");
+		tempMap.put("greek", "greek");
+		tempMap.put("hungarian", "latin2");
+		tempMap.put("italian", "latin1");
+		tempMap.put("japanese", "ujis");
+		tempMap.put("japanese-sjis", "sjis");
+		tempMap.put("korean", "euckr");
+		tempMap.put("norwegian", "latin1");
+		tempMap.put("norwegian-ny", "latin1");
+		tempMap.put("polish", "latin2");
+		tempMap.put("portuguese", "latin1");
+		tempMap.put("romanian", "latin2");
+		tempMap.put("russian", "koi8r");
+		tempMap.put("serbian", "cp1250");
+		tempMap.put("slovak", "latin2");
+		tempMap.put("spanish", "latin1");
+		tempMap.put("swedish", "latin1");
+		tempMap.put("ukrainian", "koi8u");
+		
+		ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP = 
+			Collections.unmodifiableMap(tempMap);
 	}
 
 	final static String getJavaEncodingForMysqlEncoding(String mysqlEncoding,
@@ -407,7 +439,7 @@
 		
 		if (conn != null && conn.versionMeetsMinimum(4, 1, 0) && 
 				"latin1".equalsIgnoreCase(mysqlEncoding)) {
-			return "cp1252";
+			return "Cp1252";
 		}
 		
 		return (String) MYSQL_TO_JAVA_CHARSET_MAP.get(mysqlEncoding);
@@ -466,6 +498,65 @@
 														// key
 	}
 
+	/**
+	 * Returns the character encoding for error messages returned from the
+	 * server. Doesn't return useful values other than Cp1252 until the driver
+	 * has gone through initialization phase and determined server configuration,
+	 * as not enough information is available to make an intelligent decision
+	 * until then.
+	 * 
+	 * @param conn the connection to the MySQL server
+	 * @return the Java encoding name that error messages use
+	 * @throws SQLException if determination of the character encoding fails
+	 */
+	final static String getCharacterEncodingForErrorMessages(Connection conn) throws
SQLException {
+		String errorMessageFile = conn.getServerVariable("language");
+		
+		if (errorMessageFile == null || errorMessageFile.length() == 0) {
+			// punt
+			return "Cp1252";
+		}
+		
+		int endWithoutSlash = errorMessageFile.length();
+		
+		if (errorMessageFile.endsWith("/") || errorMessageFile.endsWith("\\")) {
+			endWithoutSlash--;
+		}
+			
+		int lastSlashIndex = errorMessageFile.lastIndexOf('/', endWithoutSlash - 1);
+		
+		if (lastSlashIndex == -1) {
+			lastSlashIndex = errorMessageFile.lastIndexOf('\\', endWithoutSlash - 1);
+		}
+		
+		if (lastSlashIndex == -1) {
+			lastSlashIndex = 0;
+		}
+		
+		if (lastSlashIndex == endWithoutSlash || endWithoutSlash < lastSlashIndex) {
+			// punt
+			return "Cp1252";
+		}
+		
+		errorMessageFile = errorMessageFile.substring(lastSlashIndex + 1, endWithoutSlash);
+		
+		String errorMessageEncodingMysql =
(String)ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP.get(errorMessageFile);
+		
+		if (errorMessageEncodingMysql == null) {
+			// punt
+			return "Cp1252";
+		}
+		
+		String javaEncoding = getJavaEncodingForMysqlEncoding(errorMessageEncodingMysql, conn);
+		
+		if (javaEncoding == null) {
+			// punt
+			return "Cp1252";
+		}
+		
+		return javaEncoding;
+	}
+	
 	final static boolean isAliasForSjis(String encoding) {
 		return ("SJIS".equalsIgnoreCase(encoding)
 				|| "WINDOWS-31J".equalsIgnoreCase(encoding)

Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/Connection.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/Connection.java	2006-06-16 00:01:41
UTC (rev 5396)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/Connection.java	2006-06-16 17:12:26
UTC (rev 5397)
@@ -516,6 +516,7 @@
 	private int origPortToConnectTo;
 	private String origDatabaseToConnectTo;
 	
+	private String errorMessageEncoding = "Cp1252"; // to begin with, changes after we talk
to the server
 	
 	/**
 	 * Creates a connection to a MySQL Server.
@@ -3040,6 +3041,9 @@
 			}
 		}
 
+		this.errorMessageEncoding = 
+			CharsetMapping.getCharacterEncodingForErrorMessages(this);
+		
 		boolean overrideDefaultAutocommit = false;
 		
 		String initConnectValue = (String) this.serverVariables
@@ -4685,4 +4689,8 @@
 	public void setInGlobalTx(boolean flag) {
 		this.isInGlobalTx = flag;
 	}
+	
+	protected String getErrorMessageEncoding() {
+		return errorMessageEncoding;
+	}
 }

Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java	2006-06-16 00:01:41
UTC (rev 5396)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/MysqlIO.java	2006-06-16 17:12:26
UTC (rev 5397)
@@ -569,7 +569,8 @@
 
                 String xOpen = null;
 
-                serverErrorMessage = resultPacket.readString();
+                serverErrorMessage = 
+                	resultPacket.readString(this.connection.getErrorMessageEncoding());
 
                 if (serverErrorMessage.startsWith("#")) { //$NON-NLS-1$
 
@@ -619,7 +620,8 @@
                 }
             }
 
-            serverErrorMessage = resultPacket.readString();
+            serverErrorMessage = resultPacket.readString(
+            		this.connection.getErrorMessageEncoding());
             clearInputStream();
 
             if (serverErrorMessage.indexOf(Messages.getString("MysqlIO.70")) != -1) {
//$NON-NLS-1$
@@ -1069,16 +1071,16 @@
                 }
 
                 // User/Password data
-                packet.writeString(user);
+                packet.writeString(user, "Cp1252");
 
                 if (this.protocolVersion > 9) {
-                    packet.writeString(Util.newCrypt(password, this.seed));
+                    packet.writeString(Util.newCrypt(password, this.seed), "Cp1252");
                 } else {
-                    packet.writeString(Util.oldCrypt(password, this.seed));
+                    packet.writeString(Util.oldCrypt(password, this.seed), "Cp1252");
                 }
 
                 if (this.useConnectWithDb) {
-                    packet.writeString(database);
+                    packet.writeString(database, "Cp1252");
                 }
 
                 send(packet, packet.getPosition());
@@ -2400,18 +2402,18 @@
         }
 
         // User/Password data
-        packet.writeString(user);
+        packet.writeString(user, "Cp1252");
 
         if (password.length() != 0) {
             /* Prepare false scramble  */
-            packet.writeString(FALSE_SCRAMBLE);
+            packet.writeString(FALSE_SCRAMBLE, "Cp1252");
         } else {
             /* For empty password*/
-            packet.writeString(""); //$NON-NLS-1$
+            packet.writeString("", "Cp1252"); //$NON-NLS-1$
         }
 
         if (this.useConnectWithDb) {
-            packet.writeString(database);
+            packet.writeString(database, "Cp1252");
         }
 
         send(packet, packet.getPosition());
@@ -2489,7 +2491,7 @@
                                     mysqlScrambleBuff), password);
 
                         Buffer packet2 = new Buffer(packLength);
-                        packet2.writeString(scrambledPassword);
+                        packet2.writeString(scrambledPassword, "Cp1252");
                         this.packetSequence++;
 
                         send(packet2, 24);

Thread
Connector/J commit: r5397 - in branches: branch_5_0/connector-j branch_5_0/connector-j/src/com/mysql/jdbc branch_5_1/connector-j branch_5_1/connector-...mmatthews16 Jun