List:Commits« Previous MessageNext Message »
From:mmatthews Date:April 22 2007 2:14am
Subject:Connector/J commit: r6406 - branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional
View as plain text  
Added:
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4StatementWrapper.java
Modified:
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4ConnectionWrapper.java
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/StatementWrapper.java
   branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java
Log:
Support for unwrapping on statements, prepared statements.

Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4ConnectionWrapper.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4ConnectionWrapper.java	2007-04-20 21:43:11 UTC (rev 6405)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4ConnectionWrapper.java	2007-04-22 02:14:34 UTC (rev 6406)
@@ -291,8 +291,6 @@
 		}
 	}
 	
-	private Map unwrappedInterfaces = null;
-
 	/**
 	 * @see java.sql.Connection#createBlob()
 	 */
@@ -337,66 +335,4 @@
 
 		return null; // never reached, but compiler can't tell
 	}
-	
-	private static final SQLException SQL_EXCEPTION_INSTANCE = new SQLException();
-	
-	class ConnectionErrorFiringInvocationHandler implements InvocationHandler {
-		Object invokeOn = null;
-		
-		public ConnectionErrorFiringInvocationHandler(Object toInvokeOn) {
-			invokeOn = toInvokeOn;
-		}
-		
-		public Object invoke(Object proxy, Method method,
-				Object[] args) throws Throwable {
-			Object result = null;
-
-			try {
-				result = method.invoke(invokeOn, args);
-				
-				if (result != null) {
-					Class[] interfaces = result.getClass().getInterfaces();
-					
-					if (interfaces.length > 0) {
-						
-						// TODO: Cache this
-						Method[] resultMethods = result.getClass().getMethods();
-						
-						for (int i = 0; i < resultMethods.length; i++) {
-							Class[] exceptionTypes = resultMethods[i].getExceptionTypes();
-							
-							boolean needsWrapped = false;
-							
-							for (int j = 0; j < exceptionTypes.length; j++) {
-								if (exceptionTypes[j].isInstance(SQL_EXCEPTION_INSTANCE)) {
-									// Needs to be wrapped too - to catch SQLExceptions
-									// and fire events if needed
-									
-									needsWrapped = true;
-									
-									break;
-								}
-							}
-							
-							if (needsWrapped) {
-								result = Proxy.newProxyInstance(result.getClass()
-										.getClassLoader(), interfaces,
-										new ConnectionErrorFiringInvocationHandler(result));
-								break;
-							}
-						}
-					}
-				}
-			} catch (InvocationTargetException e) {
-				if (e.getTargetException() instanceof SQLException) {
-					checkAndFireConnectionError((SQLException) e
-							.getTargetException());
-				} else {
-					throw e;
-				}
-			}
-
-			return result;
-		}
-	}
 }

Added: branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java	2007-04-20 21:43:11 UTC (rev 6405)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java	2007-04-22 02:14:34 UTC (rev 6406)
@@ -0,0 +1,513 @@
+/*
+ Copyright (C) 2002-2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as 
+ published by the Free Software Foundation.
+
+ There are special exceptions to the terms and conditions of the GPL 
+ as it is applied to this software. View the full text of the 
+ exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
+ software distribution.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+
+ */
+package com.mysql.jdbc.jdbc2.optional;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.RowId;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import com.mysql.jdbc.ConnectionImpl;
+import com.mysql.jdbc.SQLError;
+import com.mysql.jdbc.jdbc2.optional.ConnectionWrapper;
+import com.mysql.jdbc.jdbc2.optional.MysqlPooledConnection;
+
+/**
+ */
+public class JDBC4PreparedStatementWrapper extends PreparedStatementWrapper {
+
+	JDBC4PreparedStatementWrapper(ConnectionWrapper c, MysqlPooledConnection conn,
+			PreparedStatement toWrap) {
+		super(c, conn, toWrap);
+	}
+	
+	public void close() throws SQLException {
+		try {
+			super.close();
+		} finally {
+			this.unwrappedInterfaces = null;
+		}
+	}
+	
+	public boolean isClosed() throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				return this.wrappedStmt.isClosed();
+			} else {
+				throw SQLError.createSQLException("Statement already closed",
+						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+		
+		return false; // never get here - compiler can't tell
+	}
+	
+	public void setPoolable(boolean poolable) throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				this.wrappedStmt.setPoolable(poolable);
+			} else {
+				throw SQLError.createSQLException("Statement already closed",
+						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+	
+	public boolean isPoolable() throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				return this.wrappedStmt.isPoolable();
+			} else {
+				throw SQLError.createSQLException("Statement already closed",
+						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+		
+		return false; // never get here - compiler can't tell
+	}
+    
+	public void setRowId(int parameterIndex, RowId x) throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setRowId(parameterIndex,
+						x);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+	
+	public void setNClob(int parameterIndex, NClob value) throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setNClob(parameterIndex,
+						value);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+
+	public void setSQLXML(int parameterIndex, SQLXML xmlObject)
+			throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setSQLXML(parameterIndex,
+						xmlObject);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+	
+	
+	public void setNString(int parameterIndex,
+            String value)
+            throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setNString(parameterIndex,
+						value);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+            
+    public void setNCharacterStream(int parameterIndex,
+                    Reader value,
+                    long length)
+                    throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setNCharacterStream(parameterIndex,
+						value, length);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+
+    public void setClob(int parameterIndex,
+            Reader reader,
+            long length)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setClob(parameterIndex,
+						reader, length);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}	
+    }
+    
+    public void setBlob(int parameterIndex,
+            InputStream inputStream,
+            long length)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setBlob(parameterIndex,
+						inputStream, length);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setNClob(int parameterIndex,
+            Reader reader,
+            long length)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setNClob(parameterIndex,
+						reader, length);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setAsciiStream(int parameterIndex,
+            InputStream x,
+            long length)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setAsciiStream(parameterIndex,
+						x, length);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setBinaryStream(int parameterIndex,
+            InputStream x,
+            long length)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setBinaryStream(parameterIndex,
+						x, length);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setCharacterStream(int parameterIndex,
+            Reader reader,
+            long length)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setCharacterStream(parameterIndex,
+						reader, length);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setAsciiStream(int parameterIndex,
+            InputStream x)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setAsciiStream(parameterIndex,
+						x);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setBinaryStream(int parameterIndex,
+            InputStream x)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setBinaryStream(parameterIndex,
+						x);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setCharacterStream(int parameterIndex,
+            Reader reader)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setCharacterStream(parameterIndex,
+						reader);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    	
+    }
+    
+    public void setNCharacterStream(int parameterIndex,
+            Reader value)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setNCharacterStream(parameterIndex,
+						value);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    	
+    }
+    
+    public void setClob(int parameterIndex,
+            Reader reader)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setClob(parameterIndex,
+						reader);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    	
+    }
+    
+    public void setBlob(int parameterIndex,
+            InputStream inputStream)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setBlob(parameterIndex,
+						inputStream);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+    
+    public void setNClob(int parameterIndex,
+            Reader reader)
+            throws SQLException {
+    	try {
+			if (this.wrappedStmt != null) {
+				((PreparedStatement) this.wrappedStmt).setNClob(parameterIndex,
+						reader);
+			} else {
+				throw SQLError.createSQLException(
+						"No operations allowed after statement closed",
+						SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+    }
+	
+	/**
+	 * Returns true if this either implements the interface argument or is
+	 * directly or indirectly a wrapper for an object that does. Returns false
+	 * otherwise. If this implements the interface then return true, else if
+	 * this is a wrapper then return the result of recursively calling
+	 * <code>isWrapperFor</code> on the wrapped object. If this does not
+	 * implement the interface and is not a wrapper, return false. This method
+	 * should be implemented as a low-cost operation compared to
+	 * <code>unwrap</code> so that callers can use this method to avoid
+	 * expensive <code>unwrap</code> calls that may fail. If this method
+	 * returns true then calling <code>unwrap</code> with the same argument
+	 * should succeed.
+	 * 
+	 * @param interfaces
+	 *            a Class defining an interface.
+	 * @return true if this implements the interface or directly or indirectly
+	 *         wraps an object that does.
+	 * @throws java.sql.SQLException
+	 *             if an error occurs while determining whether this is a
+	 *             wrapper for an object with the given interface.
+	 * @since 1.6
+	 */
+	public boolean isWrapperFor(Class<?> iface) throws SQLException {
+
+		boolean isInstance = iface.isInstance(this);
+
+		if (isInstance) {
+			return true;
+		}
+
+		return (iface.isInstance(com.mysql.jdbc.Statement.class) 
+				|| iface.isInstance(java.sql.Statement.class) 
+				|| iface.isInstance(java.sql.PreparedStatement.class)
+				|| iface.isInstance(java.sql.Wrapper.class));
+	}
+
+	/**
+	 * Returns an object that implements the given interface to allow access to
+	 * non-standard methods, or standard methods not exposed by the proxy. The
+	 * result may be either the object found to implement the interface or a
+	 * proxy for that object. If the receiver implements the interface then that
+	 * is the object. If the receiver is a wrapper and the wrapped object
+	 * implements the interface then that is the object. Otherwise the object is
+	 * the result of calling <code>unwrap</code> recursively on the wrapped
+	 * object. If the receiver is not a wrapper and does not implement the
+	 * interface, then an <code>SQLException</code> is thrown.
+	 * 
+	 * @param iface
+	 *            A Class defining an interface that the result must implement.
+	 * @return an object that implements the interface. May be a proxy for the
+	 *         actual implementing object.
+	 * @throws java.sql.SQLException
+	 *             If no object found that implements the interface
+	 * @since 1.6
+	 */
+	public synchronized <T> T unwrap(java.lang.Class<T> iface)
+			throws java.sql.SQLException {
+		try {
+			if ("java.sql.Statement".equals(iface.getName()) 
+					|| "java.sql.PreparedStatement".equals(iface.getName()) 
+					|| "java.sql.Wrapper.class".equals(iface.getName())) {
+				return iface.cast(this);
+			}
+			
+			if (unwrappedInterfaces == null) {
+				unwrappedInterfaces = new HashMap();
+			}
+			
+			Object cachedUnwrapped = unwrappedInterfaces.get(iface);
+			
+			if (cachedUnwrapped == null) {
+				if (cachedUnwrapped == null) {
+					cachedUnwrapped = Proxy.newProxyInstance(
+							this.wrappedStmt.getClass().getClassLoader(), 
+							new Class[] { iface },
+							new ConnectionErrorFiringInvocationHandler(this.wrappedStmt));
+					unwrappedInterfaces.put(iface, cachedUnwrapped);
+				}
+				unwrappedInterfaces.put(iface, cachedUnwrapped);
+			}
+			
+			return iface.cast(cachedUnwrapped);
+		} catch (ClassCastException cce) {
+			throw SQLError.createSQLException("Unable to unwrap to "
+					+ iface.toString(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+		}
+	}
+}

Added: branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4StatementWrapper.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4StatementWrapper.java	2007-04-20 21:43:11 UTC (rev 6405)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/JDBC4StatementWrapper.java	2007-04-22 02:14:34 UTC (rev 6406)
@@ -0,0 +1,192 @@
+/*
+ Copyright (C) 2002-2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as 
+ published by the Free Software Foundation.
+
+ There are special exceptions to the terms and conditions of the GPL 
+ as it is applied to this software. View the full text of the 
+ exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
+ software distribution.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+
+ */
+package com.mysql.jdbc.jdbc2.optional;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.NClob;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import com.mysql.jdbc.ConnectionImpl;
+import com.mysql.jdbc.SQLError;
+import com.mysql.jdbc.jdbc2.optional.ConnectionWrapper;
+import com.mysql.jdbc.jdbc2.optional.MysqlPooledConnection;
+
+/**
+ */
+public class JDBC4StatementWrapper extends StatementWrapper {
+
+	protected JDBC4StatementWrapper(ConnectionWrapper c, 
+			MysqlPooledConnection conn,
+			Statement toWrap) {
+		super(c, conn, toWrap);
+	}
+	
+	public void close() throws SQLException {
+		try {
+			super.close();
+		} finally {
+			this.unwrappedInterfaces = null;
+		}
+	}
+	
+	public boolean isClosed() throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				return this.wrappedStmt.isClosed();
+			} else {
+				throw SQLError.createSQLException("Statement already closed",
+						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+	
+	public void setPoolable(boolean poolable) throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				this.wrappedStmt.setPoolable(poolable);
+			} else {
+				throw SQLError.createSQLException("Statement already closed",
+						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+	
+	public boolean isPoolable() throws SQLException {
+		try {
+			if (this.wrappedStmt != null) {
+				return this.wrappedStmt.isPoolable();
+			} else {
+				throw SQLError.createSQLException("Statement already closed",
+						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+			}
+		} catch (SQLException sqlEx) {
+			checkAndFireConnectionError(sqlEx);
+		}
+	}
+    
+	/**
+	 * Returns true if this either implements the interface argument or is
+	 * directly or indirectly a wrapper for an object that does. Returns false
+	 * otherwise. If this implements the interface then return true, else if
+	 * this is a wrapper then return the result of recursively calling
+	 * <code>isWrapperFor</code> on the wrapped object. If this does not
+	 * implement the interface and is not a wrapper, return false. This method
+	 * should be implemented as a low-cost operation compared to
+	 * <code>unwrap</code> so that callers can use this method to avoid
+	 * expensive <code>unwrap</code> calls that may fail. If this method
+	 * returns true then calling <code>unwrap</code> with the same argument
+	 * should succeed.
+	 * 
+	 * @param interfaces
+	 *            a Class defining an interface.
+	 * @return true if this implements the interface or directly or indirectly
+	 *         wraps an object that does.
+	 * @throws java.sql.SQLException
+	 *             if an error occurs while determining whether this is a
+	 *             wrapper for an object with the given interface.
+	 * @since 1.6
+	 */
+	public boolean isWrapperFor(Class<?> iface) throws SQLException {
+
+		boolean isInstance = iface.isInstance(this);
+
+		if (isInstance) {
+			return true;
+		}
+
+		return (iface.isInstance(com.mysql.jdbc.Statement.class)
+				|| iface.isInstance(java.sql.Statement.class)
+				|| iface.isInstance(java.sql.Wrapper.class));
+	}
+
+	/**
+	 * Returns an object that implements the given interface to allow access to
+	 * non-standard methods, or standard methods not exposed by the proxy. The
+	 * result may be either the object found to implement the interface or a
+	 * proxy for that object. If the receiver implements the interface then that
+	 * is the object. If the receiver is a wrapper and the wrapped object
+	 * implements the interface then that is the object. Otherwise the object is
+	 * the result of calling <code>unwrap</code> recursively on the wrapped
+	 * object. If the receiver is not a wrapper and does not implement the
+	 * interface, then an <code>SQLException</code> is thrown.
+	 * 
+	 * @param iface
+	 *            A Class defining an interface that the result must implement.
+	 * @return an object that implements the interface. May be a proxy for the
+	 *         actual implementing object.
+	 * @throws java.sql.SQLException
+	 *             If no object found that implements the interface
+	 * @since 1.6
+	 */
+	public synchronized <T> T unwrap(java.lang.Class<T> iface)
+			throws java.sql.SQLException {
+		try {
+			if ("java.sql.Statement".equals(iface.getName())
+					|| "java.sql.Wrapper.class".equals(iface.getName())) {
+				return iface.cast(this);
+			}
+			
+			if (unwrappedInterfaces == null) {
+				unwrappedInterfaces = new HashMap();
+			}
+			
+			Object cachedUnwrapped = unwrappedInterfaces.get(iface);
+			
+			if (cachedUnwrapped == null) {
+				cachedUnwrapped = Proxy.newProxyInstance(
+						this.wrappedStmt.getClass().getClassLoader(), 
+						new Class[] { iface },
+						new ConnectionErrorFiringInvocationHandler(this.wrappedStmt));
+				unwrappedInterfaces.put(iface, cachedUnwrapped);
+			}
+			
+			return iface.cast(cachedUnwrapped);
+		} catch (ClassCastException cce) {
+			throw SQLError.createSQLException("Unable to unwrap to "
+					+ iface.toString(), SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+		}
+	}
+}

Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/StatementWrapper.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/StatementWrapper.java	2007-04-20 21:43:11 UTC (rev 6405)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/StatementWrapper.java	2007-04-22 02:14:34 UTC (rev 6406)
@@ -25,7 +25,6 @@
 package com.mysql.jdbc.jdbc2.optional;
 
 import com.mysql.jdbc.SQLError;
-import com.mysql.jdbc.exceptions.NotYetImplementedException;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
@@ -827,55 +826,4 @@
 			checkAndFireConnectionError(sqlEx);
 		}
 	}
-//
-//	public boolean isClosed() throws SQLException {
-//		try {
-//			if (this.wrappedStmt != null) {
-//				return this.wrappedStmt.isClosed();
-//			} else {
-//				throw SQLError.createSQLException("Statement already closed",
-//						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-//			}
-//		} catch (SQLException sqlEx) {
-//			checkAndFireConnectionError(sqlEx);
-//		}
-//		
-//		return true;
-//	}
-//
-//	public boolean isPoolable() throws SQLException {
-//		try {
-//			if (this.wrappedStmt != null) {
-//				return this.wrappedStmt.isPoolable();
-//			} else {
-//				throw SQLError.createSQLException("Statement already closed",
-//						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-//			}
-//		} catch (SQLException sqlEx) {
-//			checkAndFireConnectionError(sqlEx);
-//		}
-//		
-//		return true;
-//	}
-//
-//	public void setPoolable(boolean poolable) throws SQLException {
-//		try {
-//			if (this.wrappedStmt != null) {
-//				this.wrappedStmt.setPoolable(poolable);
-//			} else {
-//				throw SQLError.createSQLException("Statement already closed",
-//						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-//			}
-//		} catch (SQLException sqlEx) {
-//			checkAndFireConnectionError(sqlEx);
-//		}
-//	}
-//
-//	public boolean isWrapperFor(Class arg0) throws SQLException {
-//		throw new NotYetImplementedException();
-//	}
-//
-//	public Object unwrap(Class arg0) throws SQLException {
-//		throw new NotYetImplementedException();
-//	}
 }

Modified: branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java
===================================================================
--- branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java	2007-04-20 21:43:11 UTC (rev 6405)
+++ branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optional/WrapperBase.java	2007-04-22 02:14:34 UTC (rev 6406)
@@ -24,7 +24,12 @@
  */
 package com.mysql.jdbc.jdbc2.optional;
 
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.sql.SQLException;
+import java.util.Map;
 
 import com.mysql.jdbc.SQLError;
 
@@ -58,4 +63,50 @@
 
 		throw sqlEx;
 	}
+	
+	protected Map unwrappedInterfaces = null;
+
+	protected class ConnectionErrorFiringInvocationHandler implements InvocationHandler {
+		Object invokeOn = null;
+		
+		public ConnectionErrorFiringInvocationHandler(Object toInvokeOn) {
+			invokeOn = toInvokeOn;
+		}
+		
+		public Object invoke(Object proxy, Method method,
+				Object[] args) throws Throwable {
+			Object result = null;
+
+			try {
+				result = method.invoke(invokeOn, args);
+				
+				if (result != null) {
+					Class[] interfaces = result.getClass().getInterfaces();
+					
+					for (int i = 0; i < interfaces.length; i++) {
+						String packageName = interfaces[i].getPackage().getName();
+						
+						if ("java.sql".equals(packageName) || 
+								"javax.sql".equals(packageName)) {
+							// needs wrapped
+							
+							result = Proxy.newProxyInstance(result.getClass()
+									.getClassLoader(), interfaces,
+									new ConnectionErrorFiringInvocationHandler(result));
+							break;
+						}
+					}
+				}
+			} catch (InvocationTargetException e) {
+				if (e.getTargetException() instanceof SQLException) {
+					checkAndFireConnectionError((SQLException) e
+							.getTargetException());
+				} else {
+					throw e;
+				}
+			}
+
+			return result;
+		}
+	}
 }
\ No newline at end of file

Thread
Connector/J commit: r6406 - branches/branch_5_1/connector-j/src/com/mysql/jdbc/jdbc2/optionalmmatthews22 Apr