Java Mailing List Archive

http://www.gg3721.com/

Home » Hibernate Commits List »

[hibernate-commits] Hibernate SVN: r15430 - in
 core/branches/Branch_3_2: src/org/hibernate and 9 other directories.

hibernate-commits

2008-10-29


Author LoginPost Reply
Author: gbadner
Date: 2008-10-29 01:38:54 -0400 (Wed, 29 Oct 2008)
New Revision: 15430

Added:
 core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateExceptionConverterJDBC4.java
 core/branches/Branch_3_2/src/org/hibernate/exception/TransactionRollbackException.java
 core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapperProxy.java
 core/branches/Branch_3_2/src/org/hibernate/lob/BlobImplProxy.java
 core/branches/Branch_3_2/src/org/hibernate/lob/ClobImplProxy.java
 core/branches/Branch_3_2/src/org/hibernate/lob/LobCreator.java
 core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorFactory.java
 core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC3.java
 core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC4.java
 core/branches/Branch_3_2/src/org/hibernate/lob/SerializableBlobProxy.java
 core/branches/Branch_3_2/src/org/hibernate/lob/SerializableClobProxy.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/AbstractBlobFromLobCreatorTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/AbstractBlobTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/AbstractClobFromLobCreatorTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/AbstractClobTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/BlobFromLobCreatorDefaultTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/BlobFromLobCreatorJDBC3ConnRelOnCloseTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/BlobFromLobCreatorJDBC3Test.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/BlobFromLobCreatorJDBC4ConnRelOnCloseTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/BlobFromLobCreatorJDBC4Test.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/ClobFromLobCreatorDefaultTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/ClobFromLobCreatorJDBC3ConnRelOnCloseTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/ClobFromLobCreatorJDBC3Test.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/ClobFromLobCreatorJDBC4ConnRelOnCloseTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/ClobFromLobCreatorJDBC4Test.java
Removed:
 core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapper.java
Modified:
 core/branches/Branch_3_2/etc/log4j.properties
 core/branches/Branch_3_2/src/org/hibernate/Hibernate.java
 core/branches/Branch_3_2/src/org/hibernate/cfg/Environment.java
 core/branches/Branch_3_2/src/org/hibernate/cfg/Settings.java
 core/branches/Branch_3_2/src/org/hibernate/cfg/SettingsFactory.java
 core/branches/Branch_3_2/src/org/hibernate/dialect/Dialect.java
 core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateConverter.java
 core/branches/Branch_3_2/src/org/hibernate/jdbc/ColumnNameCache.java
 core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java
 core/branches/Branch_3_2/src/org/hibernate/lob/BlobImpl.java
 core/branches/Branch_3_2/src/org/hibernate/lob/ClobImpl.java
 core/branches/Branch_3_2/src/org/hibernate/lob/SerializableBlob.java
 core/branches/Branch_3_2/src/org/hibernate/lob/SerializableClob.java
 core/branches/Branch_3_2/src/org/hibernate/type/BlobType.java
 core/branches/Branch_3_2/src/org/hibernate/type/ClobType.java
 core/branches/Branch_3_2/test/org/hibernate/test/AllTests.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/BlobTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/ClobTest.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/LobHolder.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/MaterializedBlobType.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/SerializableData.java
 core/branches/Branch_3_2/test/org/hibernate/test/lob/SerializableTypeTest.java
Log:
HHH-2412 : Make Hibernate compilable with JDK 1.6


Modified: core/branches/Branch_3_2/etc/log4j.properties
===================================================================
--- core/branches/Branch_3_2/etc/log4j.properties  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/etc/log4j.properties  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
#log4j.logger.org.hibernate.hql.ast.AST=debug

### log just the SQL
-#log4j.logger.org.hibernate.SQL=debug
+log4j.logger.org.hibernate.SQL=debug

### log JDBC bind parameters ###
-log4j.logger.org.hibernate.type=info
-#log4j.logger.org.hibernate.type=debug
+#log4j.logger.org.hibernate.type=info
+log4j.logger.org.hibernate.type=debug

### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=debug

Modified: core/branches/Branch_3_2/src/org/hibernate/Hibernate.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/Hibernate.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/Hibernate.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
import org.hibernate.engine.HibernateIterator;
import org.hibernate.intercept.FieldInterceptionHelper;
import org.hibernate.intercept.FieldInterceptor;
-import org.hibernate.lob.BlobImpl;
-import org.hibernate.lob.ClobImpl;
-import org.hibernate.lob.SerializableBlob;
-import org.hibernate.lob.SerializableClob;
+import org.hibernate.lob.LobCreator;
+import org.hibernate.lob.LobCreatorFactory;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.AnyType;
@@(protected) @@
 }

 /**
+   * If the setting for Environment#USE_CONNECTION_FOR_LOB_CREATION is true, then the
+   * returned LobCreator will use the Connection to create LOBs. If it is false, then
+   * the returned LobCreator will not use the Connection to create LOBs.
+   *
+   * If the property is not set, then the returned LobCreator will use the connection to
+   * create LOBs only if the JVM and JDBC driver support this JDBC4 functionality.
+   *
+   * (@(protected))
+   *
+   * @param session The session.
+   * @return the LobCreator
+   */
+  public static LobCreator getLobCreator(Session session) {
+    return LobCreatorFactory.createLobCreator( session );
+  }
+
+  /**
  * Create a new <tt>Blob</tt>. The returned object will be initially immutable.
  *
  * @param bytes a byte array
  * @return the Blob
  */
 public static Blob createBlob(byte[] bytes) {
-    return new SerializableBlob( new BlobImpl( bytes ) );
+    return LobCreatorFactory.createLobCreator().createBlob( bytes );
 }

 /**
@@(protected) @@
  * @param length the number of bytes in the stream
  * @return the Blob
  */
-  public static Blob createBlob(InputStream stream, int length) {
-    return new SerializableBlob( new BlobImpl( stream, length ) );
+  public static Blob createBlob(InputStream stream, int length) throws HibernateException, IOException {
+    return LobCreatorFactory.createLobCreator().createBlob( stream, length );
 }

 /**
@@(protected) @@
  * @return the Blob
  * @throws IOException
  */
-  public static Blob createBlob(InputStream stream) throws IOException {
-    return new SerializableBlob( new BlobImpl( stream, stream.available() ) );
+  public static Blob createBlob(InputStream stream) throws HibernateException, IOException {
+    return LobCreatorFactory.createLobCreator().createBlob( stream, stream.available() );
 }

 /**
@@(protected) @@
  *
  * @param string a <tt>String</tt>
  */
-  public static Clob createClob(String string) {
-    return new SerializableClob( new ClobImpl( string ) );
+  public static Clob createClob(String string) throws HibernateException {
+    return LobCreatorFactory.createLobCreator().createClob( string );
 }

 /**
@@(protected) @@
  * @param reader a character stream
  * @param length the number of characters in the stream
  */
-  public static Clob createClob(Reader reader, int length) {
-    return new SerializableClob( new ClobImpl( reader, length ) );
+  public static Clob createClob(Reader reader, int length) throws HibernateException, IOException {
+    return LobCreatorFactory.createLobCreator().createClob( reader, length );
 }

 /**

Modified: core/branches/Branch_3_2/src/org/hibernate/cfg/Environment.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/cfg/Environment.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/cfg/Environment.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
*  this property when using user supplied connections)</td>
* </tr>
* <tr>
- *  <td><tt>hibernate.jdbc.use_getGeneratedKeys</tt></td>
+ *  <td><tt>hibernate.jdbc.use_get_generated_keys</tt></td>
*  <td>enable use of JDBC3 PreparedStatement.getGeneratedKeys() to retrieve
*  natively generated keys after insert. Requires JDBC3+ driver and JRE1.4+</td>
* </tr>
* <tr>
+ *  <td><tt>hibernate.jdbc.use_connection_for_lob_creation</tt></td>
+ *  <td>enable use of JDBC4 Connection.createBlob() and Connection.createClob() to
+ *  create Blobs and Clobs. Requires JDBC4+ driver and JRE1.6+</td>
+ * </tr>
+ * <tr>
*  <td><tt>hibernate.hbm2ddl.auto</tt></td>
*  <td>enable auto DDL export</td>
* </tr>
@@(protected) @@
  */
 public static final String USE_GET_GENERATED_KEYS = "hibernate.jdbc.use_get_generated_keys";
 /**
+   * Tells the JDBC driver to attempt to create Blobs and Clobs using JDBC 4.0
+   * Connection.createBlob() and Connection.createClob(), respectively.
+   * Performance may be better if this property is set to true and the underlying JDBC driver
+   * supports these Connection methods.
+   */
+  public static final String USE_CONNECTION_FOR_LOB_CREATION = "hibernate.jdbc.use_connection_for_lob_creation";
+  /**
  * Gives the JDBC driver a hint as to the number of rows that should be fetched from the database
  * when more rows are needed. If <tt>0</tt>, JDBC driver default settings will be used.
  */
@@(protected) @@
 private static final boolean JVM_HAS_TIMESTAMP_BUG;
 private static final boolean JVM_HAS_JDK14_TIMESTAMP;
 private static final boolean JVM_SUPPORTS_GET_GENERATED_KEYS;
+  private static final boolean JVM_SUPPORTS_JDBC4;

 private static final Properties GLOBAL_PROPERTIES;
 private static final HashMap ISOLATION_LEVELS = new HashMap();
@@(protected) @@
   JVM_SUPPORTS_GET_GENERATED_KEYS = getGeneratedKeysSupport;
   if (!JVM_SUPPORTS_GET_GENERATED_KEYS) log.info("JVM does not support Statement.getGeneratedKeys()");

+    boolean jvmSupportsJDBC4;
+    try {
+      Connection.class.getMethod("createBlob", null);
+      Connection.class.getMethod("createClob", null);
+      jvmSupportsJDBC4 = true;
+    }
+    catch (NoSuchMethodException nsme) {
+      jvmSupportsJDBC4 = false;
+    }
+    JVM_SUPPORTS_JDBC4 = jvmSupportsJDBC4;
+    if (!JVM_SUPPORTS_JDBC4 ) log.info("JVM does not support JDBC4");
+
   boolean linkedHashSupport;
   try {
     Class.forName("java.util.LinkedHashSet");
@@(protected) @@
   return JVM_SUPPORTS_GET_GENERATED_KEYS;
 }

+  public static boolean jvmSupportsJDBC4() {
+    return JVM_SUPPORTS_JDBC4;
+  }
+
 /**
  * Should we use streams to bind binary types to JDBC IN parameters.
  * Property <tt>hibernate.jdbc.use_streams_for_binary</tt>.

Modified: core/branches/Branch_3_2/src/org/hibernate/cfg/Settings.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/cfg/Settings.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/cfg/Settings.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
 private int defaultBatchFetchSize;
 private boolean scrollableResultSetsEnabled;
 private boolean getGeneratedKeysEnabled;
+  private boolean useConnectionForLobCreationEnabled;
 private String defaultSchemaName;
 private String defaultCatalogName;
 private Integer jdbcFetchSize;
@@(protected) @@
   return getGeneratedKeysEnabled;
 }

+  public boolean isUseConnectionForLobCreationEnabled() {
+    return useConnectionForLobCreationEnabled;
+  }
+
 public boolean isMinimalPutsEnabled() {
   return minimalPutsEnabled;
 }
@@(protected) @@
   getGeneratedKeysEnabled = b;
 }

+  void setUseConnectionForLobCreationEnabled(boolean b) {
+    useConnectionForLobCreationEnabled = b;    
+  }
+
 void setJdbcFetchSize(Integer integer) {
   jdbcFetchSize = integer;
 }

Modified: core/branches/Branch_3_2/src/org/hibernate/cfg/SettingsFactory.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/cfg/SettingsFactory.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/cfg/SettingsFactory.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
   boolean metaSupportsBatchUpdates = false;
   boolean metaReportsDDLCausesTxnCommit = false;
   boolean metaReportsDDLInTxnSupported = true;
+    boolean driverConnectionHasLobCreationMethods = false;

   // 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
   // The need for it is intended to be alleviated with 3.3 developement, thus it is
@@(protected) @@
           }
         }

+          if ( Environment.jvmSupportsJDBC4() ) {
+            try {
+              // this block doesn't actually use the DatabaseMetaData, but it does use the
+              // driver Connection Class to determine if methods are present.
+              Class c = conn.getClass();
+              if ( Connection.class.equals( c.getMethod( "createBlob", null ).getDeclaringClass() ) ||
+                Connection.class.equals( c.getMethod( "createClob", null ).getDeclaringClass() ) ) {
+                driverConnectionHasLobCreationMethods = false;
+              }
+              else {
+                // the driver's Connection class has all three methods;
+                // can't tell if the driver actually supports these methods w/o calling them,
+                // but don't want to actually create a LOB here.
+                driverConnectionHasLobCreationMethods = true;
+              }
+            }
+            catch (AbstractMethodError ame) {
+              driverConnectionHasLobCreationMethods = false;
+            }
+            catch (Exception e) {
+              driverConnectionHasLobCreationMethods = false;
+            }
+          }
       }
+
       finally {
         connections.closeConnection(conn);
       }
@@(protected) @@
   log.info("JDBC3 getGeneratedKeys(): " + enabledDisabled(useGetGeneratedKeys) );
   settings.setGetGeneratedKeysEnabled(useGetGeneratedKeys);

+    boolean useConnectionForLobCreation = PropertiesHelper.getBoolean(Environment.USE_CONNECTION_FOR_LOB_CREATION, properties, driverConnectionHasLobCreationMethods);
+    log.info("JDBC4 Connection.createBlob() and Connection.createClob(): " + enabledDisabled(useConnectionForLobCreation) );
+    settings.setUseConnectionForLobCreationEnabled(useConnectionForLobCreation);
+
   Integer statementFetchSize = PropertiesHelper.getInteger(Environment.STATEMENT_FETCH_SIZE, properties);
   if (statementFetchSize!=null) log.info("JDBC result set fetch size: " + statementFetchSize);
   settings.setJdbcFetchSize(statementFetchSize);

Modified: core/branches/Branch_3_2/src/org/hibernate/dialect/Dialect.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/dialect/Dialect.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/dialect/Dialect.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
package org.hibernate.dialect;

import java.sql.CallableStatement;
@@(protected) @@
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.exception.SQLStateConverter;
import org.hibernate.exception.ViolatedConstraintNameExtracter;
+import org.hibernate.exception.SQLStateExceptionConverterJDBC4;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.SequenceGenerator;
import org.hibernate.id.TableHiLoGenerator;
@@(protected) @@
  */
 public SQLExceptionConverter buildSQLExceptionConverter() {
   // The default SQLExceptionConverter for all dialects is based on SQLState
-    // since SQLErrorCode is extremely vendor-specific. Specific Dialects
+    // since SQLErrorCode is extremely vendor-specific. If JDBC4 is supported,
+    // then the default SQLExceptionConverter will convert based on JDBC4
+    // SQLException if the SQLState is not recognized. Specific Dialects
   // may override to return whatever is most appropriate for that vendor.
-    return new SQLStateConverter( getViolatedConstraintNameExtracter() );
+    return ( Environment.jvmSupportsJDBC4() ?
+        new SQLStateExceptionConverterJDBC4( getViolatedConstraintNameExtracter() ) :
+        new SQLStateConverter( getViolatedConstraintNameExtracter() )
+    );
 }

 private static final ViolatedConstraintNameExtracter EXTRACTER = new ViolatedConstraintNameExtracter() {

Modified: core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateConverter.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateConverter.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateConverter.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
 private static final Set DATA_CATEGORIES = new HashSet();
 private static final Set INTEGRITY_VIOLATION_CATEGORIES = new HashSet();
 private static final Set CONNECTION_CATEGORIES = new HashSet();
+  private static final Set TRANSACTION_ROLLBACK_CATEGORIES = new HashSet();

 static {
   SQL_GRAMMAR_CATEGORIES.add( "07" );
@@(protected) @@
   INTEGRITY_VIOLATION_CATEGORIES.add( "44" );

   CONNECTION_CATEGORIES.add( "08" );
+    CONNECTION_CATEGORIES.add( "28" );
+
+    TRANSACTION_ROLLBACK_CATEGORIES.add( "40" );
 }

 public SQLStateConverter(ViolatedConstraintNameExtracter extracter) {
   this.extracter = extracter;
 }

+  protected String getViolatedConstraintName(SQLException sqlException) {
+    return extracter.extractConstraintName( sqlException );
+  }
+
 /**
  * Convert the given SQLException into Hibernate's JDBCException hierarchy.
  *
@@(protected) @@
         return new SQLGrammarException( message, sqlException, sql );
       }
       else if ( INTEGRITY_VIOLATION_CATEGORIES.contains( sqlStateClassCode ) ) {
-          String constraintName = extracter.extractConstraintName( sqlException );
+          String constraintName = getViolatedConstraintName( sqlException );
         return new ConstraintViolationException( message, sqlException, sql, constraintName );
       }
       else if ( CONNECTION_CATEGORIES.contains( sqlStateClassCode ) ) {
@@(protected) @@
       else if ( DATA_CATEGORIES.contains( sqlStateClassCode ) ) {
         return new DataException( message, sqlException, sql );
       }
+        else if ( TRANSACTION_ROLLBACK_CATEGORIES.contains( sqlStateClassCode ) ) {
+          return new TransactionRollbackException( message, sqlException, sql );
+        }
     }

     if ( "40001".equals( sqlState ) ) {

Added: core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateExceptionConverterJDBC4.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateExceptionConverterJDBC4.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/exception/SQLStateExceptionConverterJDBC4.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+// $Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * A SQLExceptionConverter implementation which performs converion based on
+ * the underlying SQLState. Interpretation of a SQL error based on SQLState
+ * is not nearly as accurate as using the ErrorCode (which is, however, vendor-
+ * specific). Use of a ErrorCode-based converter should be preferred approach
+ * for converting/interpreting SQLExceptions.
+ *
+ * @author Gail Badner
+ */
+public class SQLStateExceptionConverterJDBC4 extends SQLStateConverter {
+
+  public SQLStateExceptionConverterJDBC4(ViolatedConstraintNameExtracter extracter) {
+    super( extracter );
+  }
+
+  /**
+   * Convert the given SQLException into Hibernate's JDBCException hierarchy.
+   *
+   * @param sqlException The SQLException to be converted.
+   * @param message    An optional error message.
+   * @param sql       Optionally, the sql being performed when the exception occurred.
+   * @return The resulting JDBCException.
+   */
+  public JDBCException convert(SQLException sqlException, String message, String sql) {
+    JDBCException jdbcException = super.convert( sqlException, message, sql );
+    if ( !( jdbcException instanceof GenericJDBCException) ) {
+      return jdbcException;
+    }
+
+    try {
+      if ( Class.forName( "java.sql.SQLIntegrityConstraintViolationException" ).isInstance( sqlException ) ) {
+        String constraintName = getViolatedConstraintName( sqlException );
+        return new ConstraintViolationException( message, sqlException, sql, constraintName );
+      }
+      else if ( Class.forName( "java.sql.SQLTransactionRollbackException" ).isInstance( sqlException ) ) {
+        return new TransactionRollbackException( message, sqlException, sql );
+      }
+      else if ( Class.forName( "java.sql.SQLClientInfoException" ).isInstance( sqlException ) ||
+          Class.forName( "java.sql.SQLInvalidAuthorizationSpecException" ).isInstance( sqlException ) ||
+          Class.forName( "java.sql.SQLNonTransientConnectionException" ).isInstance( sqlException ) ||
+          Class.forName( "java.sql.SQLTransientConnectionException" ).isInstance( sqlException ) ) {
+        return new JDBCConnectionException( message, sqlException, sql );
+      }
+      else if ( Class.forName( "java.sql.SQLSyntaxErrorException" ).isInstance( sqlException ) ) {
+        return new SQLGrammarException( message, sqlException, sql );
+      }
+      else if ( Class.forName( "java.sql.SQLDataException" ).isInstance( sqlException ) ||
+          Class.forName( "javax.sql.rowset.serial.SerialException" ).isInstance( sqlException ) ) {
+        return new DataException( message, sqlException, sql );
+      }
+    }
+    catch ( ClassNotFoundException e ) {
+      // log because either config is messed up or there's a typo in a class name
+    }
+    return jdbcException;
+  }
+}
\ No newline at end of file

Added: core/branches/Branch_3_2/src/org/hibernate/exception/TransactionRollbackException.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/exception/TransactionRollbackException.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/exception/TransactionRollbackException.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+// $Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.exception;
+
+import org.hibernate.JDBCException;
+
+import java.sql.SQLException;
+
+/**
+ * Implementation of JDBCException that indicates that the current statement
+ * was automatically rolled back by the database becuase of deadlock or other
+ * transaction serialization failures.
+ *
+ * @author Gail Badner
+ */
+public class TransactionRollbackException extends JDBCException {
+  /**
+   * Constructor for TransactionRollbackException.
+   *
+   * @param message Optional message.
+   * @param root   The underlying exception.
+   */
+  public TransactionRollbackException(String message, SQLException root) {
+    super( message, root );
+  }
+
+  /**
+   * Constructor for TransactionRollbackException.
+   *
+   * @param message Optional message.
+   * @param root   The underlying exception.
+   * @param sql   the SQL statement involved in the exception.
+   */
+  public TransactionRollbackException(String message, SQLException root, String sql) {
+    super( message, root, sql );
+  }
+}
\ No newline at end of file

Modified: core/branches/Branch_3_2/src/org/hibernate/jdbc/ColumnNameCache.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/jdbc/ColumnNameCache.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/jdbc/ColumnNameCache.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
// $Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
package org.hibernate.jdbc;

import java.sql.SQLException;
+import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

@@(protected) @@
   this.columnNameToIndexCache = new HashMap( columnCount );
 }

-  public int getIndexForColumnName(String columnName, ResultSetWrapper rs)throws SQLException {
+  public int getIndexForColumnName(String columnName, ResultSet rs) throws SQLException {
   Integer cached = ( Integer ) columnNameToIndexCache.get( columnName );
   if ( cached != null ) {
     return cached.intValue();
   }
   else {
-      int index = rs.getTarget().findColumn( columnName );
+      int index = rs.findColumn( columnName );
     columnNameToIndexCache.put( columnName, new Integer(index) );
     return index;
   }

Deleted: core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapper.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapper.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapper.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
-// $Id$
-package org.hibernate.jdbc;
-
-import java.io.InputStream;
-import java.io.Reader;
-import java.math.BigDecimal;
-import java.net.URL;
-import java.sql.Array;
-import java.sql.Blob;
-import java.sql.Clob;
-import java.sql.Date;
-import java.sql.Ref;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.SQLWarning;
-import java.sql.Statement;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.util.Calendar;
-import java.util.Map;
-
-/**
- * A ResultSet delegate, responsible for locally caching the columnName-to-columnIndex
- * resolution that has been found to be inefficient in a few vendor's drivers (i.e., Oracle
- * and Postgres).
- *
- * @author Steve Ebersole
- */
-public class ResultSetWrapper implements ResultSet {
-
-  private ResultSet rs;
-  private ColumnNameCache columnNameCache;
-
-  public ResultSetWrapper(ResultSet resultSet, ColumnNameCache columnNameCache) {
-    this.rs = resultSet;
-    this.columnNameCache = columnNameCache;
-  }
-
-  /*package*/ ResultSet getTarget() {
-    return rs;
-  }
-
-
-  // ResultSet impl ("overridden") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-  /**
-   * Overridden version to utilize local caching of the column indexes by name
-   * to improve performance for those drivers which are known to not support
-   * such caching by themselves.
-   * <p/>
-   * This implementation performs the caching based on the upper case version
-   * of the given column name.
-   *
-   * @param columnName The column name to resolve into an index.
-   * @return The column index corresponding to the given column name.
-   * @throws SQLException - if the ResultSet object does not contain
-   * columnName or a database access error occurs
-   */
-  public int findColumn(String columnName) throws SQLException {
-    return columnNameCache.getIndexForColumnName( columnName, this );
-  }
-
-  public Array getArray(String colName) throws SQLException {
-    return rs.getArray( findColumn(colName) );
-  }
-
-  public void updateArray(String columnName, Array x) throws SQLException {
-    rs.updateArray( findColumn(columnName), x );
-  }
-
-  public InputStream getAsciiStream(String columnName) throws SQLException {
-    return rs.getAsciiStream( findColumn(columnName) );
-  }
-
-  public void updateAsciiStream(String columnName, InputStream x, int length) throws SQLException {
-    rs.updateAsciiStream( findColumn(columnName), x, length );
-  }
-
-  public BigDecimal getBigDecimal(String columnName) throws SQLException {
-    return rs.getBigDecimal( findColumn(columnName) );
-  }
-
-  public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
-    return rs.getBigDecimal( findColumn(columnName), scale );
-  }
-
-  public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
-    rs.updateBigDecimal( findColumn(columnName), x );
-  }
-
-  public InputStream getBinaryStream(String columnName) throws SQLException {
-    return rs.getBinaryStream( findColumn(columnName) );
-  }
-
-  public void updateBinaryStream(String columnName, InputStream x, int length) throws SQLException {
-    rs.updateBinaryStream( findColumn(columnName), x, length );
-  }
-
-  public Blob getBlob(String columnName) throws SQLException {
-    return rs.getBlob( findColumn(columnName) );
-  }
-
-  public void updateBlob(String columnName, Blob x) throws SQLException {
-    rs.updateBlob( findColumn(columnName), x );
-  }
-
-  public boolean getBoolean(String columnName) throws SQLException {
-    return rs.getBoolean( findColumn(columnName) );
-  }
-
-  public void updateBoolean(String columnName, boolean x) throws SQLException {
-    rs.updateBoolean( findColumn(columnName), x );
-  }
-
-  public byte getByte(String columnName) throws SQLException {
-    return rs.getByte( findColumn(columnName) );
-  }
-
-  public void updateByte(String columnName, byte x) throws SQLException {
-    rs.updateByte( findColumn(columnName), x );
-  }
-
-  public byte[] getBytes(String columnName) throws SQLException {
-    return rs.getBytes( findColumn(columnName) );
-  }
-
-  public void updateBytes(String columnName, byte[] x) throws SQLException {
-    rs.updateBytes( findColumn(columnName), x );
-  }
-
-  public Reader getCharacterStream(String columnName) throws SQLException {
-    return rs.getCharacterStream( findColumn(columnName) );
-  }
-
-  public void updateCharacterStream(String columnName, Reader x, int length) throws SQLException {
-    rs.updateCharacterStream( findColumn(columnName), x, length );
-  }
-
-  public Clob getClob(String columnName) throws SQLException {
-    return rs.getClob( findColumn(columnName) );
-  }
-
-  public void updateClob(String columnName, Clob x) throws SQLException {
-    rs.updateClob( findColumn(columnName), x );
-  }
-
-  public Date getDate(String columnName) throws SQLException {
-    return rs.getDate( findColumn(columnName) );
-  }
-
-  public Date getDate(String columnName, Calendar cal) throws SQLException {
-    return rs.getDate( findColumn(columnName), cal );
-  }
-
-  public void updateDate(String columnName, Date x) throws SQLException {
-    rs.updateDate( findColumn(columnName), x );
-  }
-
-  public double getDouble(String columnName) throws SQLException {
-    return rs.getDouble( findColumn(columnName) );
-  }
-
-  public void updateDouble(String columnName, double x) throws SQLException {
-    rs.updateDouble( findColumn(columnName), x );
-  }
-
-  public float getFloat(String columnName) throws SQLException {
-    return rs.getFloat( findColumn(columnName) );
-  }
-
-  public void updateFloat(String columnName, float x) throws SQLException {
-    rs.updateFloat( findColumn(columnName), x );
-  }
-
-  public int getInt(String columnName) throws SQLException {
-    return rs.getInt( findColumn(columnName) );
-  }
-
-  public void updateInt(String columnName, int x) throws SQLException {
-    rs.updateInt( findColumn(columnName), x );
-  }
-
-  public long getLong(String columnName) throws SQLException {
-    return rs.getLong( findColumn(columnName) );
-  }
-
-  public void updateLong(String columnName, long x) throws SQLException {
-    rs.updateLong( findColumn(columnName), x );
-  }
-
-  public Object getObject(String columnName) throws SQLException {
-    return rs.getObject( findColumn(columnName) );
-  }
-
-  public Object getObject(String columnName, Map map) throws SQLException {
-    return rs.getObject( findColumn(columnName), map );
-  }
-
-  public void updateObject(String columnName, Object x) throws SQLException {
-    rs.updateObject( findColumn(columnName), x );
-  }
-
-  public void updateObject(String columnName, Object x, int scale) throws SQLException {
-    rs.updateObject( findColumn(columnName), x, scale );
-  }
-
-  public Ref getRef(String columnName) throws SQLException {
-    return rs.getRef( findColumn(columnName) );
-  }
-
-  public void updateRef(String columnName, Ref x) throws SQLException {
-    rs.updateRef( findColumn(columnName), x );
-  }
-
-  public short getShort(String columnName) throws SQLException {
-    return rs.getShort( findColumn(columnName) );
-  }
-
-  public void updateShort(String columnName, short x) throws SQLException {
-    rs.updateShort( findColumn(columnName), x );
-  }
-
-  public String getString(String columnName) throws SQLException {
-    return rs.getString( findColumn(columnName) );
-  }
-
-  public void updateString(String columnName, String x) throws SQLException {
-    rs.updateString( findColumn(columnName), x );
-  }
-
-  public Time getTime(String columnName) throws SQLException {
-    return rs.getTime( findColumn(columnName) );
-  }
-
-  public Time getTime(String columnName, Calendar cal) throws SQLException {
-    return rs.getTime( findColumn(columnName), cal );
-  }
-
-  public void updateTime(String columnName, Time x) throws SQLException {
-    rs.updateTime( findColumn(columnName), x );
-  }
-
-  public Timestamp getTimestamp(String columnName) throws SQLException {
-    return rs.getTimestamp( findColumn(columnName) );
-  }
-
-  public void updateTimestamp(String columnName, Timestamp x) throws SQLException {
-    rs.updateTimestamp( findColumn(columnName), x );
-  }
-
-  public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException {
-    return rs.getTimestamp( findColumn(columnName), cal );
-  }
-
-  public InputStream getUnicodeStream(String columnName) throws SQLException {
-    return rs.getUnicodeStream( findColumn(columnName) );
-  }
-
-  public URL getURL(String columnName) throws SQLException {
-    return rs.getURL( findColumn(columnName) );
-  }
-
-  public void updateNull(String columnName) throws SQLException {
-    rs.updateNull( findColumn(columnName) );
-  }
-
-
-  // ResultSet impl (delegated) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-  public int getConcurrency() throws SQLException {
-    return rs.getConcurrency();
-  }
-
-  public int getFetchDirection() throws SQLException {
-    return rs.getFetchDirection();
-  }
-
-  public int getFetchSize() throws SQLException {
-    return rs.getFetchSize();
-  }
-
-  public int getRow() throws SQLException {
-    return rs.getRow();
-  }
-
-  public int getType() throws SQLException {
-    return rs.getType();
-  }
-
-  public void afterLast() throws SQLException {
-    rs.afterLast();
-  }
-
-  public void beforeFirst() throws SQLException {
-    rs.beforeFirst();
-  }
-
-  public void cancelRowUpdates() throws SQLException {
-    rs.cancelRowUpdates();
-  }
-
-  public void clearWarnings() throws SQLException {
-    rs.clearWarnings();
-  }
-
-  public void close() throws SQLException {
-    rs.close();
-  }
-
-  public void deleteRow() throws SQLException {
-    rs.deleteRow();
-  }
-
-  public void insertRow() throws SQLException {
-    rs.insertRow();
-  }
-
-  public void moveToCurrentRow() throws SQLException {
-    rs.moveToCurrentRow();
-  }
-
-  public void moveToInsertRow() throws SQLException {
-    rs.moveToInsertRow();
-  }
-
-  public void refreshRow() throws SQLException {
-    rs.refreshRow();
-  }
-
-  public void updateRow() throws SQLException {
-    rs.updateRow();
-  }
-
-  public boolean first() throws SQLException {
-    return rs.first();
-  }
-
-  public boolean isAfterLast() throws SQLException {
-    return rs.isAfterLast();
-  }
-
-  public boolean isBeforeFirst() throws SQLException {
-    return rs.isBeforeFirst();
-  }
-
-  public boolean isFirst() throws SQLException {
-    return rs.isFirst();
-  }
-
-  public boolean isLast() throws SQLException {
-    return rs.isLast();
-  }
-
-  public boolean last() throws SQLException {
-    return rs.last();
-  }
-
-  public boolean next() throws SQLException {
-    return rs.next();
-  }
-
-  public boolean previous() throws SQLException {
-    return rs.previous();
-  }
-
-  public boolean rowDeleted() throws SQLException {
-    return rs.rowDeleted();
-  }
-
-  public boolean rowInserted() throws SQLException {
-    return rs.rowInserted();
-  }
-
-  public boolean rowUpdated() throws SQLException {
-    return rs.rowUpdated();
-  }
-
-  public boolean wasNull() throws SQLException {
-    return rs.wasNull();
-  }
-
-  public byte getByte(int columnIndex) throws SQLException {
-    return rs.getByte(columnIndex);
-  }
-
-  public double getDouble(int columnIndex) throws SQLException {
-    return rs.getDouble(columnIndex);
-  }
-
-  public float getFloat(int columnIndex) throws SQLException {
-    return rs.getFloat(columnIndex);
-  }
-
-  public int getInt(int columnIndex) throws SQLException {
-    return rs.getInt(columnIndex);
-  }
-
-  public long getLong(int columnIndex) throws SQLException {
-    return rs.getLong(columnIndex);
-  }
-
-  public short getShort(int columnIndex) throws SQLException {
-    return rs.getShort(columnIndex);
-  }
-
-  public void setFetchDirection(int direction) throws SQLException {
-    rs.setFetchDirection(direction);
-  }
-
-  public void setFetchSize(int rows) throws SQLException {
-    rs.setFetchSize(rows);
-  }
-
-  public void updateNull(int columnIndex) throws SQLException {
-    rs.updateNull(columnIndex);
-  }
-
-  public boolean absolute(int row) throws SQLException {
-    return rs.absolute(row);
-  }
-
-  public boolean getBoolean(int columnIndex) throws SQLException {
-    return rs.getBoolean(columnIndex);
-  }
-
-  public boolean relative(int rows) throws SQLException {
-    return rs.relative(rows);
-  }
-
-  public byte[] getBytes(int columnIndex) throws SQLException {
-    return rs.getBytes(columnIndex);
-  }
-
-  public void updateByte(int columnIndex, byte x) throws SQLException {
-    rs.updateByte(columnIndex, x);
-  }
-
-  public void updateDouble(int columnIndex, double x) throws SQLException {
-    rs.updateDouble(columnIndex, x);
-  }
-
-  public void updateFloat(int columnIndex, float x) throws SQLException {
-    rs.updateFloat(columnIndex, x);
-  }
-
-  public void updateInt(int columnIndex, int x) throws SQLException {
-    rs.updateInt(columnIndex, x);
-  }
-
-  public void updateLong(int columnIndex, long x) throws SQLException {
-    rs.updateLong(columnIndex, x);
-  }
-
-  public void updateShort(int columnIndex, short x) throws SQLException {
-    rs.updateShort(columnIndex, x);
-  }
-
-  public void updateBoolean(int columnIndex, boolean x) throws SQLException {
-    rs.updateBoolean(columnIndex, x);
-  }
-
-  public void updateBytes(int columnIndex, byte[] x) throws SQLException {
-    rs.updateBytes(columnIndex, x);
-  }
-
-  public InputStream getAsciiStream(int columnIndex) throws SQLException {
-    return rs.getAsciiStream(columnIndex);
-  }
-
-  public InputStream getBinaryStream(int columnIndex) throws SQLException {
-    return rs.getBinaryStream(columnIndex);
-  }
-
-  public InputStream getUnicodeStream(int columnIndex) throws SQLException {
-    return rs.getUnicodeStream(columnIndex);
-  }
-
-  public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {
-    rs.updateAsciiStream(columnIndex, x, length);
-  }
-
-  public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
-    rs.updateBinaryStream(columnIndex, x, length);
-  }
-
-  public Reader getCharacterStream(int columnIndex) throws SQLException {
-    return rs.getCharacterStream(columnIndex);
-  }
-
-  public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
-    rs.updateCharacterStream(columnIndex, x, length);
-  }
-
-  public Object getObject(int columnIndex) throws SQLException {
-    return rs.getObject(columnIndex);
-  }
-
-  public void updateObject(int columnIndex, Object x) throws SQLException {
-    rs.updateObject(columnIndex, x);
-  }
-
-  public void updateObject(int columnIndex, Object x, int scale) throws SQLException {
-    rs.updateObject(columnIndex, x, scale);
-  }
-
-  public String getCursorName() throws SQLException {
-    return rs.getCursorName();
-  }
-
-  public String getString(int columnIndex) throws SQLException {
-    return rs.getString(columnIndex);
-  }
-
-  public void updateString(int columnIndex, String x) throws SQLException {
-    rs.updateString(columnIndex, x);
-  }
-
-  public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
-    return rs.getBigDecimal(columnIndex);
-  }
-
-  public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
-    return rs.getBigDecimal(columnIndex, scale);
-  }
-
-  public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
-    rs.updateBigDecimal(columnIndex, x);
-  }
-
-  public URL getURL(int columnIndex) throws SQLException {
-    return rs.getURL(columnIndex);
-  }
-
-  public Array getArray(int columnIndex) throws SQLException {
-    return rs.getArray(columnIndex);
-  }
-
-  public void updateArray(int columnIndex, Array x) throws SQLException {
-    rs.updateArray(columnIndex, x);
-  }
-
-  public Blob getBlob(int columnIndex) throws SQLException {
-    return rs.getBlob(columnIndex);
-  }
-
-  public void updateBlob(int columnIndex, Blob x) throws SQLException {
-    rs.updateBlob(columnIndex, x);
-  }
-
-  public Clob getClob(int columnIndex) throws SQLException {
-    return rs.getClob(columnIndex);
-  }
-
-  public void updateClob(int columnIndex, Clob x) throws SQLException {
-    rs.updateClob(columnIndex, x);
-  }
-
-  public Date getDate(int columnIndex) throws SQLException {
-    return rs.getDate(columnIndex);
-  }
-
-  public void updateDate(int columnIndex, Date x) throws SQLException {
-    rs.updateDate(columnIndex, x);
-  }
-
-  public Ref getRef(int columnIndex) throws SQLException {
-    return rs.getRef(columnIndex);
-  }
-
-  public void updateRef(int columnIndex, Ref x) throws SQLException {
-    rs.updateRef(columnIndex, x);
-  }
-
-  public ResultSetMetaData getMetaData() throws SQLException {
-    return rs.getMetaData();
-  }
-
-  public SQLWarning getWarnings() throws SQLException {
-    return rs.getWarnings();
-  }
-
-  public Statement getStatement() throws SQLException {
-    return rs.getStatement();
-  }
-
-  public Time getTime(int columnIndex) throws SQLException {
-    return rs.getTime(columnIndex);
-  }
-
-  public void updateTime(int columnIndex, Time x) throws SQLException {
-    rs.updateTime(columnIndex, x);
-  }
-
-  public Timestamp getTimestamp(int columnIndex) throws SQLException {
-    return rs.getTimestamp(columnIndex);
-  }
-
-  public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
-    rs.updateTimestamp(columnIndex, x);
-  }
-
-  public Object getObject(int columnIndex, Map map) throws SQLException {
-    return rs.getObject( columnIndex, map );
-  }
-
-  public Date getDate(int columnIndex, Calendar cal) throws SQLException {
-    return rs.getDate(columnIndex, cal);
-  }
-
-  public Time getTime(int columnIndex, Calendar cal) throws SQLException {
-    return rs.getTime(columnIndex, cal);
-  }
-
-  public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
-    return rs.getTimestamp(columnIndex, cal);
-  }
-}
-

Added: core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapperProxy.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapperProxy.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/jdbc/ResultSetWrapperProxy.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+//$Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jdbc;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.util.JDBCExceptionReporter;
+
+/**
+ * A proxy for a ResultSet delegate, responsible for locally caching the
+ * columnName-to-columnIndex resolution that has been found to be inefficient
+ * in a few vendor's drivers (i.e., Oracle and Postgres).
+ *
+ * @author Gail Badner
+ */
+public class ResultSetWrapperProxy implements InvocationHandler {
+
+  private static final Class[] PROXY_INTERFACES = new Class[] { ResultSet.class };
+  private static final Log log = LogFactory.getLog( ResultSetWrapperProxy.class );
+
+  private final ResultSet rs;
+  private ColumnNameCache columnNameCache;
+
+  /**
+   * Generates a proxy wrapping the ResultSet.
+   *
+   * @param resultSet The resultSet to wrap.
+   * @param columnNameCache The cache storing data for converting column names to column indexes.
+   * @return The generated proxy.
+   */
+  public static ResultSet generateProxy(ResultSet resultSet, ColumnNameCache columnNameCache) {
+    return ( ResultSet ) Proxy.newProxyInstance(
+        getProxyClassLoader(),
+        PROXY_INTERFACES,
+        new ResultSetWrapperProxy( resultSet, columnNameCache )
+    );
+  }
+
+  private ResultSetWrapperProxy(ResultSet resultSet, ColumnNameCache columnNameCache) {
+    this.rs = resultSet;
+    this.columnNameCache = columnNameCache;
+  }
+
+  /**
+   * Overridden version to utilize local caching of the column indexes by name
+   * to improve performance for those drivers which are known to not support
+   * such caching by themselves.
+   * <p/>
+   * This implementation performs the caching based on the upper case version
+   * of the given column name.
+   *
+   * @param columnName The column name to resolve into an index.
+   * @return The column index corresponding to the given column name.
+   * @throws java.sql.SQLException - if the ResultSet object does not contain
+   * columnName or a database access error occurs
+   */
+  public int findColumn(String columnName) throws SQLException {
+    return columnNameCache.getIndexForColumnName( columnName, rs );
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+    if ( isFirstArgColumnLabel( method, args ) ) {
+      try {
+        int columnIndex = findColumn( ( String ) args[0] );
+        return invokeMethod( getMethodUsingColumnIndex( method ), getArgsUsingColumnIndex( args, columnIndex ) );
+      }
+      catch ( SQLException ex ) {
+        StringBuffer buf = new StringBuffer()
+            .append( "Exception getting column index for column: [" )
+            .append( args[0] )
+            .append( "].\nReverting to using: [" )
+            .append( args[ 0 ] )
+            .append( "] as first argument for method: [" )
+            .append( method )
+            .append( "]" );
+        JDBCExceptionReporter.logExceptions( ex, buf.toString() );
+      }
+      catch ( NoSuchMethodException ex ) {
+        StringBuffer buf = new StringBuffer()
+            .append( "Exception switching from method: [" )
+            .append( method )
+            .append( "] to a method using the column index. Reverting to using: [" )
+            .append( method )
+            .append( "]" );
+        if ( log.isWarnEnabled() ) {
+          log.warn( buf.toString() );
+        }
+      }
+    }
+    return invokeMethod( method, args );
+  }
+
+  private boolean isFirstArgColumnLabel(Method method, Object args[]) {
+    return method.getParameterTypes().length > 0 &&
+        method.getParameterTypes()[ 0 ].equals( String.class ) &&
+        args.length == method.getParameterTypes().length &&
+        String.class.isInstance( args[ 0 ] ) &&
+        ( method.getName().startsWith( "get" ) || method.getName().startsWith( "update" ) );
+  }
+
+  private Method getMethodUsingColumnIndex(Method method) throws NoSuchMethodException {
+    Class actualParameterTypes[] = new Class[ method.getParameterTypes().length ];
+    actualParameterTypes[0] = int.class;
+    System.arraycopy( method.getParameterTypes(), 1, actualParameterTypes, 1, method.getParameterTypes().length - 1 );
+    return method.getDeclaringClass().getMethod( method.getName(), actualParameterTypes );
+  }
+
+  private Object[] getArgsUsingColumnIndex( Object[] args, int columnIndex ) {
+    Object actualArgs[] = new Object[ args.length ];
+    actualArgs[0] = new Integer( columnIndex );
+    System.arraycopy( args, 1, actualArgs, 1, args.length - 1 );
+     return actualArgs;
+  }
+
+  private Object invokeMethod( Method method, Object args[] ) throws Throwable {
+    try {
+      return method.invoke( rs, args );
+    }
+    catch( InvocationTargetException e ) {
+      throw e.getTargetException();
+    }
+  }
+
+  /**
+   * Determines the appropriate class loader to which the generated proxy
+   * should be scoped.
+   *
+   * @return The class loader appropriate for proxy construction.
+   */
+  public static ClassLoader getProxyClassLoader() {
+    ClassLoader cl = Thread.currentThread().getContextClassLoader();
+    if ( cl == null ) {
+      cl = ResultSet.class.getClassLoader();
+    }
+    return cl;
+  }
+}
\ No newline at end of file

Modified: core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
import org.hibernate.impl.FetchingScrollableResultsImpl;
import org.hibernate.impl.ScrollableResultsImpl;
import org.hibernate.jdbc.ColumnNameCache;
-import org.hibernate.jdbc.ResultSetWrapper;
+import org.hibernate.jdbc.ResultSetWrapperProxy;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
@@(protected) @@
   if ( session.getFactory().getSettings().isWrapResultSetsEnabled() ) {
     try {
       log.debug("Wrapping result set [" + rs + "]");
-        return new ResultSetWrapper( rs, retreiveColumnNameToIndexCache( rs ) );
+        return ResultSetWrapperProxy.generateProxy( rs, retreiveColumnNameToIndexCache( rs ) );
     }
     catch(SQLException e) {
       log.info("Error wrapping result set", e);

Modified: core/branches/Branch_3_2/src/org/hibernate/lob/BlobImpl.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/BlobImpl.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/BlobImpl.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
package org.hibernate.lob;

-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.sql.Blob;
-import java.sql.SQLException;

/**
- * A dummy implementation of <tt>java.sql.Blob</tt> that
- * may be used to insert new data into a BLOB.
* @author Gavin King
*/
-public class BlobImpl implements Blob {
-
-  private InputStream stream;
-  private int length;
-  private boolean needsReset = false;
-
-  public BlobImpl(byte[] bytes) {
-    this.stream = new ByteArrayInputStream(bytes);
-    this.length = bytes.length;
-  }
-
-  public BlobImpl(InputStream stream, int length) {
-    this.stream = stream;
-    this.length = length;
-  }
-
-  /**
-   * @see java.sql.Blob#length()
-   */
-  public long length() throws SQLException {
-    return length;
-  }
-
-  /**
-   * @see java.sql.Blob#truncate(long)
-   */
-  public void truncate(long pos) throws SQLException {
-    excep();
-  }
-
-  /**
-   * @see java.sql.Blob#getBytes(long, int)
-   */
-  public byte[] getBytes(long pos, int len) throws SQLException {
-    excep(); return null;
-  }
-
-  /**
-   * @see java.sql.Blob#setBytes(long, byte[])
-   */
-  public int setBytes(long pos, byte[] bytes) throws SQLException {
-    excep(); return 0;
-  }
-
-  /**
-   * @see java.sql.Blob#setBytes(long, byte[], int, int)
-   */
-  public int setBytes(long pos, byte[] bytes, int i, int j)
-  throws SQLException {
-    excep(); return 0;
-  }
-
-  /**
-   * @see java.sql.Blob#position(byte[], long)
-   */
-  public long position(byte[] bytes, long pos) throws SQLException {
-    excep(); return 0;
-  }
-
-  /**
-   * @see java.sql.Blob#getBinaryStream()
-   */
-  public InputStream getBinaryStream() throws SQLException {
-    try {
-      if (needsReset) stream.reset();
-    }
-    catch (IOException ioe) {
-      throw new SQLException("could not reset reader");
-    }
-    needsReset = true;
-    return stream;
-  }
-
-  /**
-   * @see java.sql.Blob#setBinaryStream(long)
-   */
-  public OutputStream setBinaryStream(long pos) throws SQLException {
-    excep(); return null;
-  }
-
-  /**
-   * @see java.sql.Blob#position(Blob, long)
-   */
-  public long position(Blob blob, long pos) throws SQLException {
-    excep(); return 0;
-  }
-
-  private static void excep() {
-    throw new UnsupportedOperationException("Blob may not be manipulated from creating session");
-  }
-
-}
-
-
-
-
-
-
+public interface BlobImpl extends Blob {
+}
\ No newline at end of file

Added: core/branches/Branch_3_2/src/org/hibernate/lob/BlobImplProxy.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/BlobImplProxy.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/BlobImplProxy.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+//$Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+package org.hibernate.lob;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Blob;
+import java.sql.SQLException;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+/**
+ * A proxy for a dummy implementation of <tt>java.sql.Blob</tt> that
+ * is used to insert new data into a Blob when the Connection is not used
+ * for creating new Blobs.
+ *
+ * This implementation provides minimal functionality for creating a
+ * new Blob. The only operations that are supported are {@(protected)()}
+ * and {@(protected)
+ * UnsupportedOperationException.
+ *
+ * The proxy extends BlobImpl so that it can be distinguished from a Blob.
+ *
+ * @author Gail Badner
+ */
+public class BlobImplProxy implements InvocationHandler {
+
+  private static final Class[] PROXY_INTERFACES = new Class[] { BlobImpl.class };
+
+  private InputStream stream;
+  private int length;
+  private boolean needsReset = false;
+
+  /**
+   * Generates a BlobImpl proxy using byte data.
+   *
+   * @param bytes The data to be created as a Blob.
+   * @return The generated proxy.
+   */
+  public static Blob generateProxy(byte[] bytes) {
+    return ( Blob ) Proxy.newProxyInstance(
+        getProxyClassLoader(),
+        PROXY_INTERFACES,
+        new BlobImplProxy( bytes )
+    );
+  }
+
+  /**
+   * Generates a BlobImpl proxy using a given number of bytes from an InputStream.
+   *
+   * @param stream The input stream of bytes to be created as a Blob.
+   * @param length The number of bytes from stream to be written to the Blob.
+   * @return The generated proxy.
+   */
+  public static Blob generateProxy(InputStream stream, int length) {
+    return ( Blob ) Proxy.newProxyInstance(
+        getProxyClassLoader(),
+        PROXY_INTERFACES,
+        new BlobImplProxy( stream, length )
+    );
+  }
+
+  private BlobImplProxy(byte[] bytes) {
+    this.stream = new ByteArrayInputStream(bytes);
+    this.length = bytes.length;
+  }
+
+  private BlobImplProxy(InputStream stream, int length) {
+    this.stream = stream;
+    this.length = length;
+  }
+
+  /**
+   * @see java.sql.Blob#length()
+   */
+  public long length() throws SQLException {
+    return length;
+  }
+
+  /**
+   * @see java.sql.Blob#getBinaryStream()
+   */
+  public InputStream getBinaryStream() throws SQLException {
+    try {
+      if (needsReset) stream.reset();
+    }
+    catch ( IOException ioe) {
+      throw new SQLException("could not reset reader");
+    }
+    needsReset = true;
+    return stream;
+  }
+  
+  /**
+   * {@(protected)}
+   *
+   * @throws UnsupportedOperationException if any methods other than {@(protected)()}
+   * or {@(protected).
+   */
+  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+    if ( "length".equals( method.getName() ) ) {
+      return new Long( length() );
+    }
+    if ( "getBinaryStream".equals( method.getName() ) && method.getParameterTypes().length == 0) {
+      return getBinaryStream();
+    }
+    throw new UnsupportedOperationException("Blob may not be manipulated from creating session");
+  }
+
+  /**
+   * Determines the appropriate class loader to which the generated proxy
+   * should be scoped.
+   *
+   * @return The class loader appropriate for proxy construction.
+   */
+  public static ClassLoader getProxyClassLoader() {
+    ClassLoader cl = Thread.currentThread().getContextClassLoader();
+    if ( cl == null ) {
+      cl = BlobImpl.class.getClassLoader();
+    }
+    return cl;
+  }
+}
\ No newline at end of file

Modified: core/branches/Branch_3_2/src/org/hibernate/lob/ClobImpl.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/ClobImpl.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/ClobImpl.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
package org.hibernate.lob;

-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.Writer;
import java.sql.Clob;
-import java.sql.SQLException;

/**
- * A dummy implementation of <tt>java.sql.Clob</tt> that
- * may be used to insert new data into a CLOB.
* @author Gavin King
*/
-public class ClobImpl implements Clob {
-
-  private Reader reader;
-  private int length;
-  private boolean needsReset = false;
-
-  public ClobImpl(String string) {
-    reader = new StringReader(string);
-    length = string.length();
-  }
-
-  public ClobImpl(Reader reader, int length) {
-    this.reader = reader;
-    this.length = length;
-  }
-
-  /**
-   * @see java.sql.Clob#length()
-   */
-  public long length() throws SQLException {
-    return length;
-  }
-
-  /**
-   * @see java.sql.Clob#truncate(long)
-   */
-  public void truncate(long pos) throws SQLException {
-    excep();
-  }
-
-  /**
-   * @see java.sql.Clob#getAsciiStream()
-   */
-  public InputStream getAsciiStream() throws SQLException {
-    try {
-      if (needsReset) reader.reset();
-    }
-    catch (IOException ioe) {
-      throw new SQLException("could not reset reader");
-    }
-    needsReset = true;
-    return new ReaderInputStream(reader);
-  }
-
-  /**
-   * @see java.sql.Clob#setAsciiStream(long)
-   */
-  public OutputStream setAsciiStream(long pos) throws SQLException {
-    excep(); return null;
-  }
-
-  /**
-   * @see java.sql.Clob#getCharacterStream()
-   */
-  public Reader getCharacterStream() throws SQLException {
-    try {
-      if (needsReset) reader.reset();
-    }
-    catch (IOException ioe) {
-      throw new SQLException("could not reset reader");
-    }
-    needsReset = true;
-    return reader;
-  }
-
-  /**
-   * @see java.sql.Clob#setCharacterStream(long)
-   */
-  public Writer setCharacterStream(long pos) throws SQLException {
-    excep(); return null;
-  }
-
-  /**
-   * @see java.sql.Clob#getSubString(long, int)
-   */
-  public String getSubString(long pos, int len) throws SQLException {
-    excep(); return null;
-  }
-
-  /**
-   * @see java.sql.Clob#setString(long, String)
-   */
-  public int setString(long pos, String string) throws SQLException {
-    excep(); return 0;
-  }
-
-  /**
-   * @see java.sql.Clob#setString(long, String, int, int)
-   */
-  public int setString(long pos, String string, int i, int j)
-  throws SQLException {
-    excep(); return 0;
-  }
-
-  /**
-   * @see java.sql.Clob#position(String, long)
-   */
-  public long position(String string, long pos) throws SQLException {
-    excep(); return 0;
-  }
-
-  /**
-   * @see java.sql.Clob#position(Clob, long)
-   */
-  public long position(Clob colb, long pos) throws SQLException {
-    excep(); return 0;
-  }
-
-
-  private static void excep() {
-    throw new UnsupportedOperationException("Blob may not be manipulated from creating session");
-  }
-
-}
-
-
-
-
-
-
+public interface ClobImpl extends Clob {
+}
\ No newline at end of file

Added: core/branches/Branch_3_2/src/org/hibernate/lob/ClobImplProxy.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/ClobImplProxy.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/ClobImplProxy.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+//$Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+package org.hibernate.lob;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.SQLException;
+import java.sql.Clob;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+/**
+ * A proxy for a dummy implementation of <tt>java.sql.Clob</tt> that
+ * is used to insert new data into a Clob when the Connection is not used
+ * for creating new Clobs.
+ *
+ * This implementation provides minimal functionality for creating a
+ * new Clob. The only operations that are supported are {@(protected)()},
+ * {@(protected)
+ * operations will throw UnsupportedOperationException.
+ *
+ * The proxy extends ClobImpl so that it can be distinguished from a Clob.
+ *
+ * @author Gail Badner
+ */
+public class ClobImplProxy implements InvocationHandler {
+
+  private static final Class[] PROXY_INTERFACES = new Class[] { ClobImpl.class };
+
+  private Reader reader;
+  private int length;
+  private boolean needsReset = false;
+
+  /**
+   * Generates a BlobImpl proxy using a String.
+   *
+   * @param string The data to be created as a Clob.
+   * @return The generated proxy.
+   */
+  public static Clob generateProxy(String string) {
+    return ( Clob ) Proxy.newProxyInstance(
+        getProxyClassLoader(),
+        PROXY_INTERFACES,
+        new ClobImplProxy( string )
+    );
+  }
+
+  /**
+   * Generates a ClobImpl proxy using a given number of characters from a Reader.
+   *
+   * @param reader The Reader for character data to be created as a Clob.
+   * @param length The number of characters from Reader to be written to the Clob.
+   * @return The generated proxy.
+   */
+  public static Clob generateProxy(Reader reader, int length) {
+    return ( Clob ) Proxy.newProxyInstance(
+        getProxyClassLoader(),
+        PROXY_INTERFACES,
+        new ClobImplProxy( reader, length )
+    );
+  }
+
+  private ClobImplProxy(String string) {
+    reader = new StringReader(string);
+    length = string.length();
+  }
+
+  private ClobImplProxy(Reader reader, int length) {
+    this.reader = reader;
+    this.length = length;
+  }
+
+  /**
+   * @see java.sql.Clob#length()
+   */
+  public long length() throws SQLException {
+    return length;
+  }
+
+  /**
+   * @see java.sql.Clob#getAsciiStream()
+   */
+  public InputStream getAsciiStream() throws SQLException {
+    reset();
+    return new ReaderInputStream(reader);
+  }
+
+  /**
+   * @see java.sql.Clob#getCharacterStream()
+   */
+  public Reader getCharacterStream() throws SQLException {
+    reset();
+    return reader;
+  }
+
+  /**
+   * {@(protected)}
+   *
+   * @throws UnsupportedOperationException if any methods other than {@(protected)()},
+   * {@(protected).
+   */
+  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+    if ( "length".equals( method.getName() ) ) {
+      return new Long( length() );
+    }
+    if ( "getAsciiStream".equals( method.getName() ) ) {
+      return getAsciiStream();
+    }
+    if ( "getCharacterStream".equals( method.getName() ) ) {
+      return getCharacterStream();
+    }
+    throw new UnsupportedOperationException("Clob may not be manipulated from creating session");
+  }
+
+  /**
+   * Determines the appropriate class loader to which the generated proxy
+   * should be scoped.
+   *
+   * @return The class loader appropriate for proxy construction.
+   */
+  public static ClassLoader getProxyClassLoader() {
+    ClassLoader cl = Thread.currentThread().getContextClassLoader();
+    if ( cl == null ) {
+      cl = ClobImpl.class.getClassLoader();
+    }
+    return cl;
+  }
+
+
+  private void reset() throws SQLException {
+    try {
+      if (needsReset) reader.reset();
+    }
+    catch (IOException ioe) {
+      throw new SQLException("could not reset reader");
+    }
+    needsReset = true;
+  }
+}
\ No newline at end of file

Added: core/branches/Branch_3_2/src/org/hibernate/lob/LobCreator.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/LobCreator.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/LobCreator.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+//$Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+package org.hibernate.lob;
+
+import java.sql.Clob;
+import java.sql.Blob;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.IOException;
+
+import org.hibernate.HibernateException;
+
+/**
+ * This interface defines the API for creating Blobs and Clobs.
+ *
+ * @author Gail Badner
+ */
+public interface LobCreator {
+
+  /**
+   * Returns a Blob object representing a SQL BLOB created from the given array of bytes.
+   *
+   * @param bytes The array of bytes to be written to this BLOB object.
+   * @return the created Blob
+   * @throws HibernateException if the Blob could not be created
+   */
+  Blob createBlob(byte[] bytes) throws HibernateException;
+
+  /**
+   * Returns a Blob object representing a SQL BLOB created from the given number of bytes
+   * from an InputStream.
+   *
+   * @param is The input stream of bytes to be written to this BLOB object.
+   * @param length The number of bytes from stream to be written to this BLOB object.
+   * @return the created Blob
+   * @throws HibernateException if the Blob could not be created
+   * @throws IOException if an I/O error occurs
+   */
+  Blob createBlob(InputStream is, int length) throws HibernateException, IOException;
+
+
+  /**
+   * Returns a Blob object representing a SQL BLOB created from the available (is.available())
+   * number of bytes from an InputStream.
+   *
+   * @param is The input stream of bytes to be written to this BLOB object.
+   * @return the created Blob
+   * @throws HibernateException if the Blob could not be created
+   * @throws IOException if an I/O error occurs
+   */
+  Blob createBlob(InputStream is) throws HibernateException, IOException;
+
+  /**
+   * Returns a Clob object representing a SQL CLOB created from the given String.
+   *
+   * @param string The String to be written to this CLOB object
+   * @throws HibernateException if the Clob could not be created
+   * @throws HibernateException
+   */
+  Clob createClob(String string) throws HibernateException;
+
+  /**
+   * Returns a Clob object representing a SQL CLOB created from the given number of
+   * characters from a character stream.
+   *
+   * @param reader The character stream to be written to this CLOB object.
+   * @param length The number of characters from reader to be written to this CLOB object.
+   * @return the created Clob
+   * @throws HibernateException if the Clob could not be created
+   * @throws IOException if an I/O error occurs
+   */
+  Clob createClob(Reader reader, int length) throws HibernateException, IOException;
+}
\ No newline at end of file

Added: core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorFactory.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorFactory.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorFactory.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+//$Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+package org.hibernate.lob;
+
+import org.hibernate.Session;
+import org.hibernate.AssertionFailure;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * A factory for creating an instance of the appropriate LobCreator implementation.
+ *
+ * @author Gail Badner
+ */
+public class LobCreatorFactory {
+
+  /**
+   * Creates an instance of a LobCreator that does not use the Connection to create LOBs.
+   * The returned LobCreator is appropriate for JVM and/or JDBC drivers that support JDBC3,
+   * but not JDBC4.
+   *
+   * @return the LobCreator
+   */
+  public static LobCreator createLobCreator() {
+    return new LobCreatorImplJDBC3();
+  }
+
+  /**
+   * If the setting for Environment#USE_CONNECTION_FOR_LOB_CREATION is true, then the
+   * returned LobCreator will use the Connection to create LOBs. If it is false, then
+   * the returned LobCreator will not use the Connection to create LOBs.
+   *
+   * If the property is not set, then the returned LobCreator will use the connection to
+   * create LOBs only if the JVM and JDBC driver support this JDBC4 functionality.
+   *
+   * (@(protected))
+   *
+   * @param session The session.
+   * @return the LobCreator
+   */
+  public static LobCreator createLobCreator(Session session) {
+    if ( session == null ) {
+      throw new AssertionFailure("session is null; use LobCreatorFactory.createLobCreator() instead.");
+    }
+    SessionFactoryImplementor sfi = ( SessionFactoryImplementor ) session.getSessionFactory();
+    if ( sfi.getSettings().isUseConnectionForLobCreationEnabled() ) {
+      return new LobCreatorImplJDBC4( session );
+    }
+    else {
+      return new LobCreatorImplJDBC3();
+    }
+  }
+}
\ No newline at end of file

Added: core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC3.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC3.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC3.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+//$Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ *
+ */
+package org.hibernate.lob;
+
+import java.sql.Blob;
+import java.sql.Clob;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.IOException;
+
+/**
+ * A LobCreator implementation that can be used with JVMs and JDBC drivers that support JDBC3.
+ *
+ * @author Gail Badner
+ */
+public class LobCreatorImplJDBC3 implements LobCreator {
+
+  /* package */
+  LobCreatorImplJDBC3() {
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Blob createBlob(byte[] bytes) {
+    return SerializableBlobProxy.generateProxy( BlobImplProxy.generateProxy( bytes ) );
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Blob createBlob(InputStream is, int length) {
+    return SerializableBlobProxy.generateProxy( BlobImplProxy.generateProxy( is, length ) );
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Blob createBlob(InputStream is) throws IOException {
+    return SerializableBlobProxy.generateProxy( BlobImplProxy.generateProxy( is, is.available() ) );
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Clob createClob(String string) {
+    return SerializableClobProxy.generateProxy( ClobImplProxy.generateProxy( string ) );
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Clob createClob(Reader reader, int length) {
+    return SerializableClobProxy.generateProxy( ClobImplProxy.generateProxy( reader, length ) );
+  }
+}

Added: core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC4.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC4.java                  (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/LobCreatorImplJDBC4.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
+// $Id: $
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.lob;
+
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import org.hibernate.Session;
+import org.hibernate.HibernateException;
+import org.hibernate.cfg.Environment;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * A LobCreator implementation that can be used with JVMs and JDBC drivers that support JDBC4.
+ *
+ * @author Gail Badner
+ */
+public class LobCreatorImplJDBC4 implements LobCreator {
+  private final SessionImplementor session;
+
+  /* package */
+  LobCreatorImplJDBC4(Session session) {
+    this.session = ( SessionImplementor ) session;
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Blob createBlob(byte[] bytes) throws HibernateException {
+    Blob blob = createBlob();
+    try {
+      blob.setBytes( 1, bytes );
+    }
+    catch ( SQLException e ) {
+      throw JDBCExceptionHelper.convert(
+              session.getFactory().getSQLExceptionConverter(),
+              e,
+              "Exception invoking adding data to a Blob."
+            );
+    }
+    return blob;
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Blob createBlob(InputStream is, int length) throws HibernateException, IOException {
+    Blob blob = createBlob();
+    try {
+      OutputStream os = blob.setBinaryStream(1);
+      byte[] data = new byte[1];
+      for ( int i = 0; i < length && is.read( data ) != -1; i++ ) {
+        os.write( data );
+      }
+      os.flush();
+      os.close();
+      return blob;
+    }
+    catch ( SQLException e ) {
+      throw JDBCExceptionHelper.convert(
+              session.getFactory().getSQLExceptionConverter(),
+              e,
+              "Exception getting OutputStream to add data to a Blob."
+            );
+    }
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Blob createBlob(InputStream is) throws HibernateException, IOException {
+    return createBlob( is, is.available() );
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Clob createClob(String string) throws HibernateException {
+    Clob clob = createClob();
+    try {
+      clob.setString( 1, string );
+      return clob;
+    }
+    catch ( SQLException e ) {
+      throw JDBCExceptionHelper.convert(
+        session.getFactory().getSQLExceptionConverter(),
+        e,
+        "Exception adding a String to a Clob."
+      );
+    }
+  }
+
+  /**
+   * {@(protected)}
+   */
+  public Clob createClob(Reader reader, int length) throws HibernateException, IOException {
+    Clob clob = createClob();
+    try {
+      Writer writer = clob.setCharacterStream( 1 );
+      char[] data = new char[1];
+      for ( int i = 0; i < length && reader.read( data ) != -1; i++ ) {
+        writer.write( data );
+      }
+      writer.flush();
+      writer.close();
+      return clob;
+    }
+    catch ( SQLException e ) {
+      throw JDBCExceptionHelper.convert(
+        session.getFactory().getSQLExceptionConverter(),
+        e,
+        "Exception getting OutputStream to add data to a Clob."
+      );
+    }
+  }
+
+  private Blob createBlob() {
+    final String CREATE_BLOB_METHOD_NAME = "createBlob";
+    return ( Blob ) invokeConnectionMethod( CREATE_BLOB_METHOD_NAME );
+  }
+
+  private Clob createClob() {
+    final String CREATE_CLOB_METHOD_NAME = "createClob";
+    return ( Clob ) invokeConnectionMethod( CREATE_CLOB_METHOD_NAME );
+  }
+
+  private Object invokeConnectionMethod(String methodName) throws HibernateException {
+    Connection connection = session.getJDBCContext().getConnectionManager().getConnection();
+    final Object emptyArray[] = { };
+    try {
+      Method method = Connection.class.getMethod( methodName, new Class[0] );
+      Object object = method.invoke( connection, emptyArray );
+      session.getJDBCContext().getConnectionManager().afterStatement();
+      return object;
+    }
+    catch ( NoSuchMethodException e ) {
+      throw new HibernateException( getMethodString( connection, methodName ) + " not supported. Set " + Environment.USE_CONNECTION_FOR_LOB_CREATION + " to false.", e );
+    }
+    catch ( AbstractMethodError e ) {
+      throw new HibernateException( "Implementation of " + getMethodString( connection, methodName ) + " not found. Set " + Environment.USE_CONNECTION_FOR_LOB_CREATION + " to false.", e );
+    }
+    catch ( InvocationTargetException e ) {
+      if ( e.getTargetException() instanceof SQLException ) {
+        throw JDBCExceptionHelper.convert(
+              session.getFactory().getSQLExceptionConverter(),
+              ( SQLException ) e.getTargetException(),
+              "Exception invoking " + getMethodString( connection, methodName )
+            );
+      }
+      throw new HibernateException( "Exception invoking " + getMethodString( connection, methodName ), e.getTargetException() );
+    }
+    catch ( IllegalAccessException e ) {
+      throw new HibernateException( "Cannot access " + getMethodString( connection, methodName ), e );
+    }
+  }
+
+  private String getMethodString(Connection connection, String methodName) {
+    return new StringBuffer()
+        .append( connection.getClass().getName() )
+        .append('.')
+        .append( methodName )
+        .append( "()" ).toString();
+  }
+}

Modified: core/branches/Branch_3_2/src/org/hibernate/lob/SerializableBlob.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/lob/SerializableBlob.java  2008-10-28 21:47:32 UTC (rev 15429)
+++ core/branches/Branch_3_2/src/org/hibernate/lob/SerializableBlob.java  2008-10-29 05:38:54 UTC (rev 15430)
@@(protected) @@
//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program i