List:Commits« Previous MessageNext Message »
From:mmatthews Date:July 5 2007 7:01pm
Subject:Connector/J commit: r6482 - in trunk/connector-j: . src/com/mysql/jdbc src/testsuite/simple
View as plain text  
Added:
   trunk/connector-j/svnmerge-commit-message.txt
Modified:
   trunk/connector-j/
   trunk/connector-j/CHANGES
   trunk/connector-j/src/com/mysql/jdbc/Field.java
   trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties
   trunk/connector-j/src/testsuite/simple/CharsetTests.java
Log:
Merged from 5.1.


Property changes on: trunk/connector-j
___________________________________________________________________
Name: svn:ignore
   - bin
build
dist
   + bin
build
dist

Name: svnmerge-integrated
   - /branches/branch_5_0:1-6478 /branches/branch_5_0/connector-j:1-5567 /branches/branch_5_1:1-6477
   + /branches/branch_5_0:1-6478 /branches/branch_5_0/connector-j:1-5567 /branches/branch_5_1:1-6477,6480

Modified: trunk/connector-j/CHANGES
===================================================================
--- trunk/connector-j/CHANGES	2007-07-04 06:05:29 UTC (rev 6481)
+++ trunk/connector-j/CHANGES	2007-07-05 19:01:07 UTC (rev 6482)
@@ -1,6 +1,23 @@
 # Changelog
 # $Id$
 
+nn-nn-07 - Version 5.1.3 Beta
+	- Setting "useBlobToStoreUTF8OutsideBMP" to "true" tells the 
+	  driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR 
+	  columns holding text encoded in UTF-8 that has characters 
+	  outside the BMP (4-byte encodings), which MySQL server 
+	  can't handle natively.
+	  
+	  Set "utf8OutsideBmpExcludedColumnNamePattern" to a regex so that
+	  column names matching the given regex will still be treated 
+	  as BLOBs The regex must follow the patterns used for the 
+	  java.util.regex package. The default is to exclude no columns, 
+	  and include all columns.
+	  
+	  Set "utf8OutsideBmpIncludedColumnNamePattern" to specify exclusion 
+	  rules to "utf8OutsideBmpExcludedColumnNamePattern". The regex must 
+	  follow the patterns used for the java.util.regex package.
+
 06-29-07 - Version 5.1.2 Beta
 
     - Setting the configuration property "rewriteBatchedStatements" 

Modified: trunk/connector-j/src/com/mysql/jdbc/Field.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/Field.java	2007-07-04 06:05:29 UTC (rev 6481)
+++ trunk/connector-j/src/com/mysql/jdbc/Field.java	2007-07-05 19:01:07 UTC (rev 6482)
@@ -27,6 +27,7 @@
 import java.io.UnsupportedEncodingException;
 import java.sql.SQLException;
 import java.sql.Types;
+import java.util.regex.PatternSyntaxException;
 
 /**
  * Field is a class used to describe fields in a ResultSet
@@ -159,8 +160,13 @@
 		if (this.mysqlType == MysqlDefs.FIELD_TYPE_BLOB) {
 			if (this.charsetIndex == 63 || 
 					!this.connection.versionMeetsMinimum(4, 1, 0)) {
-				setBlobTypeBasedOnLength();
-				this.sqlType = MysqlDefs.mysqlToJavaType(this.mysqlType);
+				if (this.connection.getUseBlobToStoreUTF8OutsideBMP() 
+						&& shouldSetupForUtf8StringInBlob()) {
+					setupForUtf8StringInBlob();
+				} else {
+					setBlobTypeBasedOnLength();
+					this.sqlType = MysqlDefs.mysqlToJavaType(this.mysqlType);
+				}
 			} else {
 				// *TEXT masquerading as blob
 				this.mysqlType = MysqlDefs.FIELD_TYPE_VAR_STRING;
@@ -276,6 +282,67 @@
 		}
 	}
 
+	private boolean shouldSetupForUtf8StringInBlob() throws SQLException {
+		String includePattern = this.connection
+				.getUtf8OutsideBmpIncludedColumnNamePattern();
+		String excludePattern = this.connection
+				.getUtf8OutsideBmpExcludedColumnNamePattern();
+
+		if (excludePattern != null
+				&& !StringUtils.isEmptyOrWhitespaceOnly(excludePattern)) {
+			try {
+				if (getOriginalName().matches(excludePattern)) {
+					if (includePattern != null
+							&& !StringUtils.isEmptyOrWhitespaceOnly(includePattern)) {
+						try {
+							if (getOriginalName().matches(includePattern)) {
+								return true;
+							}
+						} catch (PatternSyntaxException pse) {
+							SQLException sqlEx = SQLError
+									.createSQLException(
+											"Illegal regex specified for \"utf8OutsideBmpIncludedColumnNamePattern\"",
+											SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+
+							if (!this.connection.getParanoid()) {
+								sqlEx.initCause(pse);
+							}
+
+							throw sqlEx;
+						}
+					}
+					
+					return false;
+				}
+			} catch (PatternSyntaxException pse) {
+				SQLException sqlEx = SQLError
+						.createSQLException(
+								"Illegal regex specified for \"utf8OutsideBmpExcludedColumnNamePattern\"",
+								SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+
+				if (!this.connection.getParanoid()) {
+					sqlEx.initCause(pse);
+				}
+
+				throw sqlEx;
+			}
+		}
+
+		return true;
+	}
+
+	private void setupForUtf8StringInBlob() {
+		if (this.length == MysqlDefs.LENGTH_TINYBLOB || this.length == MysqlDefs.LENGTH_BLOB) {
+			this.mysqlType = MysqlDefs.FIELD_TYPE_VARCHAR;
+			this.sqlType = Types.VARCHAR;
+		}  else {
+			this.mysqlType = MysqlDefs.FIELD_TYPE_VAR_STRING;
+			this.sqlType = Types.LONGVARCHAR;
+		}
+		
+		this.charsetIndex = 33;	
+	}
+
 	/**
 	 * Constructor used when communicating with pre 4.1 servers
 	 */

Modified: trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2007-07-04 06:05:29 UTC (rev 6481)
+++ trunk/connector-j/src/com/mysql/jdbc/LocalizedErrorMessages.properties	2007-07-05 19:01:07 UTC (rev 6482)
@@ -583,6 +583,9 @@
 ConnectionProperties.trustCertificateKeyStorePassword=Password for the trusted root certificates KeyStore
 ConnectionProperties.Username=The user to connect as
 ConnectionProperties.Password=The password to use when connecting
+ConnectionProperties.useBlobToStoreUTF8OutsideBMP=Tells the driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR columns holding text encoded in UTF-8 that has characters outside the BMP (4-byte encodings), which MySQL server can't handle natively.
+ConnectionProperties.utf8OutsideBmpExcludedColumnNamePattern=When "useBlobToStoreUTF8OutsideBMP" is set to "true", column names matching the given regex will still be treated as BLOBs unless they match the regex specified for "utf8OutsideBmpIncludedColumnNamePattern". The regex must follow the patterns used for the java.util.regex package.
+ConnectionProperties.utf8OutsideBmpIncludedColumnNamePattern=Used to specify exclusion rules to "utf8OutsideBmpExcludedColumnNamePattern". The regex must follow the patterns used for the java.util.regex package.
 
 # 
 # Error Messages for Connection Properties

Modified: trunk/connector-j/src/testsuite/simple/CharsetTests.java
===================================================================
--- trunk/connector-j/src/testsuite/simple/CharsetTests.java	2007-07-04 06:05:29 UTC (rev 6481)
+++ trunk/connector-j/src/testsuite/simple/CharsetTests.java	2007-07-05 19:01:07 UTC (rev 6482)
@@ -23,7 +23,9 @@
 package testsuite.simple;
 
 import java.sql.Connection;
+import java.sql.SQLException;
 import java.sql.Statement;
+import java.sql.Types;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -290,4 +292,158 @@
 			}
 		}
 	}
+	
+	public void testUtf8OutsideBMPInBlob() throws Exception {
+		createTable("utf8Test", "(include_blob BLOB, include_tinyblob TINYBLOB, include_longblob LONGBLOB, exclude_tinyblob TINYBLOB, exclude_blob BLOB, exclude_longblob LONGBLOB)");
+		
+		// We know this gets truncated in MySQL currently, even though it's valid UTF-8, it's just 4 bytes encoded
+		String outsideBmp = new String(new byte[] {(byte) 0xF0, (byte) 0x90, (byte) 0x80, (byte) 0x80}, "UTF-8");
+		byte[] outsideBmpBytes = outsideBmp.getBytes("UTF-8");
+		System.out.println(outsideBmpBytes.length);
+		
+		Connection utf8Conn = getConnectionWithProps("useBlobToStoreUTF8OutsideBMP=true, characterEncoding=UTF-8");
+		
+		String insertStatement = "INSERT INTO utf8Test VALUES (?, ?, ?, ?, ?, ?)";
+		
+		this.pstmt = utf8Conn.prepareStatement(insertStatement);
+		
+		this.pstmt.setString(1, outsideBmp);
+		this.pstmt.setString(2, outsideBmp);
+		this.pstmt.setString(3, outsideBmp);
+		this.pstmt.setString(4, outsideBmp);
+		this.pstmt.setString(5, outsideBmp);
+		this.pstmt.setString(6, outsideBmp);
+		this.pstmt.executeUpdate();
+		
+		String query = "SELECT include_blob, include_tinyblob, include_longblob, exclude_tinyblob, exclude_blob, exclude_longblob FROM utf8Test";
+		this.rs = utf8Conn.createStatement().executeQuery(query);
+		this.rs.next();
+		
+		assertEquals(this.rs.getObject(1).toString(), outsideBmp);
+		assertEquals(this.rs.getObject(2).toString(), outsideBmp);
+		assertEquals(this.rs.getObject(3).toString(), outsideBmp);
+		assertEquals(this.rs.getObject(4).toString(), outsideBmp);
+		assertEquals(this.rs.getObject(5).toString(), outsideBmp);
+		assertEquals(this.rs.getObject(6).toString(), outsideBmp);
+		
+		assertEquals("java.lang.String", this.rs.getObject(1).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(1));
+		assertEquals(Types.VARCHAR, this.rs.getMetaData().getColumnType(1));
+		
+		assertEquals("java.lang.String", this.rs.getObject(2).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(2));
+		assertEquals(Types.VARCHAR, this.rs.getMetaData().getColumnType(2));
+		
+		assertEquals("java.lang.String", this.rs.getObject(3).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(3));
+		assertEquals(Types.LONGVARCHAR, this.rs.getMetaData().getColumnType(3));
+		
+		assertEquals("java.lang.String", this.rs.getObject(4).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(4));
+		assertEquals(Types.VARCHAR, this.rs.getMetaData().getColumnType(4));
+		
+		assertEquals("java.lang.String", this.rs.getObject(5).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(5));
+		assertEquals(Types.VARCHAR, this.rs.getMetaData().getColumnType(5));
+		
+		assertEquals("java.lang.String", this.rs.getObject(6).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(6));
+		assertEquals(Types.LONGVARCHAR, this.rs.getMetaData().getColumnType(6));
+		
+		utf8Conn = getConnectionWithProps("useBlobToStoreUTF8OutsideBMP=true, characterEncoding=UTF-8,utf8OutsideBmpIncludedColumnNamePattern=.*include.*,utf8OutsideBmpExcludedColumnNamePattern=.*blob");
+		
+		this.rs = utf8Conn.createStatement().executeQuery(query);
+		this.rs.next();
+		
+		// Should walk/talk like a string, encoded in utf-8 on the server (4-byte)
+		assertEquals(this.rs.getObject(1).toString(), outsideBmp);
+		assertEquals(this.rs.getObject(2).toString(), outsideBmp);
+		assertEquals(this.rs.getObject(3).toString(), outsideBmp);
+		
+		assertEquals("java.lang.String", this.rs.getObject(1).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(1));
+		assertEquals(Types.VARCHAR, this.rs.getMetaData().getColumnType(1));
+		
+		assertEquals("java.lang.String", this.rs.getObject(2).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(2));
+		assertEquals(Types.VARCHAR, this.rs.getMetaData().getColumnType(2));
+		
+		assertEquals("java.lang.String", this.rs.getObject(3).getClass().getName());
+		assertEquals("java.lang.String", this.rs.getMetaData().getColumnClassName(3));
+		assertEquals(Types.LONGVARCHAR, this.rs.getMetaData().getColumnType(3));
+		
+		// These should be left as a blob, since it matches the exclusion regex
+		assertTrue(bytesAreSame(this.rs.getBytes(4), outsideBmpBytes));
+		assertEquals("[B", this.rs.getObject(4).getClass().getName());
+		assertEquals("[B", this.rs.getMetaData().getColumnClassName(4));
+		assertEquals(Types.VARBINARY, this.rs.getMetaData().getColumnType(4));
+		
+		// Should behave types-wise just like BLOB, including LONGVARBINARY type mapping
+		assertTrue(bytesAreSame(this.rs.getBytes(5), outsideBmpBytes));
+		assertEquals("[B", this.rs.getObject(5).getClass().getName());
+		assertEquals("[B", this.rs.getMetaData().getColumnClassName(5));
+		assertEquals(Types.LONGVARBINARY, this.rs.getMetaData().getColumnType(5));
+		
+		assertTrue(bytesAreSame(this.rs.getBytes(6), outsideBmpBytes));
+		assertEquals("[B", this.rs.getObject(6).getClass().getName());
+		assertEquals("[B", this.rs.getMetaData().getColumnClassName(6));
+		assertEquals(Types.LONGVARBINARY, this.rs.getMetaData().getColumnType(6));
+		
+		//
+		// Check error handling
+		//
+		
+		utf8Conn = getConnectionWithProps("useBlobToStoreUTF8OutsideBMP=true, characterEncoding=UTF-8,utf8OutsideBmpIncludedColumnNamePattern={{,utf8OutsideBmpExcludedColumnNamePattern={{");
+		
+		try {
+			utf8Conn.createStatement().executeQuery(query);
+			fail("Expected an exception");
+		} catch (SQLException sqlEx) {
+			assertNotNull(sqlEx.getCause());
+			assertEquals("java.util.regex.PatternSyntaxException", sqlEx.getCause().getClass().getName());
+		}
+		
+		utf8Conn = getConnectionWithProps("useBlobToStoreUTF8OutsideBMP=true, characterEncoding=UTF-8,utf8OutsideBmpIncludedColumnNamePattern={{,utf8OutsideBmpExcludedColumnNamePattern=.*");
+		
+		try {
+			utf8Conn.createStatement().executeQuery(query);
+			fail("Expected an exception");
+		} catch (SQLException sqlEx) {
+			assertNotNull(sqlEx.getCause());
+			assertEquals("java.util.regex.PatternSyntaxException", sqlEx.getCause().getClass().getName());
+		}
+		
+		utf8Conn = getConnectionWithProps("useBlobToStoreUTF8OutsideBMP=true, characterEncoding=UTF-8,utf8OutsideBmpIncludedColumnNamePattern={{,utf8OutsideBmpExcludedColumnNamePattern={{,paranoid=true");
+		
+		try {
+			utf8Conn.createStatement().executeQuery(query);
+			fail("Expected an exception");
+		} catch (SQLException sqlEx) {
+			assertNull(sqlEx.getCause());
+		}
+		
+		utf8Conn = getConnectionWithProps("useBlobToStoreUTF8OutsideBMP=true, characterEncoding=UTF-8,utf8OutsideBmpIncludedColumnNamePattern={{,utf8OutsideBmpExcludedColumnNamePattern=.*,paranoid=true");
+		
+		try {
+			utf8Conn.createStatement().executeQuery(query);
+			fail("Expected an exception");
+		} catch (SQLException sqlEx) {
+			assertNull(sqlEx.getCause());
+		}
+		
+	}
+	
+	private boolean bytesAreSame(byte[] byte1, byte[] byte2) {
+		if (byte1.length != byte2.length) {
+			return false;
+		}
+
+		for (int i = 0; i < byte1.length; i++) {
+			if (byte1[i] != byte2[i]) {
+				return false;
+			}
+		}
+
+		return true;
+	}
 }

Added: trunk/connector-j/svnmerge-commit-message.txt
===================================================================
--- trunk/connector-j/svnmerge-commit-message.txt	2007-07-04 06:05:29 UTC (rev 6481)
+++ trunk/connector-j/svnmerge-commit-message.txt	2007-07-05 19:01:07 UTC (rev 6482)
@@ -0,0 +1,22 @@
+Merged revisions 6480 via svnmerge from 
+svn+ssh://mmatthews@stripped/connectors-svnroot/connector-j/branches/branch_5_1
+
+........
+  r6480 | mmatthews | 2007-07-04 00:47:23 -0500 (Wed, 04 Jul 2007) | 15 lines
+  
+  	- Setting "useBlobToStoreUTF8OutsideBMP" to "true" tells the 
+  	  driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR 
+  	  columns holding text encoded in UTF-8 that has characters 
+  	  outside the BMP (4-byte encodings), which MySQL server 
+  	  can't handle natively.
+  	  
+  	  Set "utf8OutsideBmpExcludedColumnNamePattern" to a regex so that
+  	  column names matching the given regex will still be treated 
+  	  as BLOBs The regex must follow the patterns used for the 
+  	  java.util.regex package. The default is to exclude no columns, 
+  	  and include all columns.
+  	  
+  	  Set "utf8OutsideBmpIncludedColumnNamePattern" to specify exclusion 
+  	  rules to "utf8OutsideBmpExcludedColumnNamePattern". The regex must 
+  	  follow the patterns used for the java.util.regex package.
+........

Thread
Connector/J commit: r6482 - in trunk/connector-j: . src/com/mysql/jdbc src/testsuite/simplemmatthews5 Jul