svn commit: r489836 - in /db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms: PlatformOracle9iImpl.java PlatformOracleImpl.java

[email protected]
Newsgroups gmane.comp.jakarta.ojb.devel
Message-ID <[email protected]>
Author: arminw
Date: Fri Dec 22 18:40:42 2006
New Revision: 489836

URL: http://svn.apache.org/viewvc?view=rev&rev=489836
Log:
refactored version

Modified:
    db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracle9iImpl.java
    db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracleImpl.java

Modified: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracle9iImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracle9iImpl.java?view=diff&rev=489836&r1=489835&r2=489836
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracle9iImpl.java (original)
+++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracle9iImpl.java Fri Dec 22 18:40:42 2006
@@ -18,18 +18,20 @@
 import java.io.ByteArrayInputStream;
 import java.lang.reflect.Method;
 import java.sql.Connection;
-import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.Types;
+import java.sql.PreparedStatement;
 import java.util.Collections;
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.ojb.broker.metadata.ConnectionPoolDescriptor;
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
 import org.apache.ojb.broker.util.ClassHelper;
 import org.apache.ojb.broker.util.UnwrapHelper;
+import org.apache.ojb.broker.util.ConvertHelper;
 import org.apache.ojb.broker.util.logging.Logger;
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 
@@ -56,9 +58,6 @@
  * TODO: Optimization: use ROWNUM to minimize the effects of not having server side cursors
  * see http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:127412348064
  *
- * @author <a href="mailto:[email protected]">Matthew Baird</a>
- * @author <a href="mailto:[email protected]">Martin Kal&eacute;n</a>
- * @author Contributions from: Erik Forkalsrud, Danilo Tommasina, Thierry Hanot, Don Lyon
  * @version CVS $Id$
  * @see Platform
  * @see PlatformDefaultImpl
@@ -66,8 +65,54 @@
  */
 public class PlatformOracle9iImpl extends PlatformOracleImpl
 {
-    private Logger logger = LoggerFactory.getLogger(PlatformOracle9iImpl.class);
+    private static Logger log = LoggerFactory.getLogger(PlatformOracle9iImpl.class);
+
+    /**
+     * Platform attribute of Oracle's native statement cache pool.
+     */
+    protected static final String ATTRIBUTE_STATEMENT_CACHE_SIZE = "platform.oracle.statementCacheSize";
+    /**
+     * Platform attribute of Oracle's native prefetch handling.
+     */
+    protected static final String ATTRIBUTE_PREFETCH_SIZE = "platform.oracle.prefetchSize";
+    /**
+     * Platform attribute to enable Oracle's native batch handling.
+     */
+    protected static final String ATTRIBUTE_BATCH_SIZE = "platform.oracle.batchSize";
+
+    protected static final Class[] PARAM_TYPE_EMPTY = {};
+    protected static final Class[] PARAM_TYPE_INTEGER = {Integer.TYPE};
+    protected static final Class[] PARAM_TYPE_BOOLEAN = {Boolean.TYPE};
+    protected static final Class[] PARAM_TYPE_STRING = {String.class};
+    protected static final Object[] PARAM_EMPTY = new Object[]{};
+    protected static final Object[] PARAM_BOOLEAN_TRUE = new Object[]{Boolean.TRUE};
+
+    protected static String JBOSS_CONN_NAME = "org.jboss.resource.adapter.jdbc.WrappedConnection";
+    protected static String ORA_CONNECTION_CLASS_NAME = "oracle.jdbc.OracleConnection";
+    protected static String ORA_STATEMENT_CLASS_NAME = "oracle.jdbc.OraclePreparedStatement";
+
+    protected Class JBOSS_CONN_CLASS;
+    protected Class ORA_CONN_CLASS;
+    protected Class ORA_PS_CLASS;
+    protected Class ORA_CLOB_CLASS;
+    protected Class ORA_BLOB_CLASS;
+    protected Class[] PARAM_TYPE_INT_ORACLOB;
+    protected Class[] PARAM_TYPE_INT_ORABLOB;
+    protected Method METHOD_SET_STATEMENT_CACHE_SIZE;
+    protected Method METHOD_SET_IMPLICIT_CACHING_ENABLED;
+    protected Method METHOD_SET_ROW_PREFETCH;
+    protected Method METHOD_SET_BLOB;
+    protected Method METHOD_SET_CLOB;
+    protected boolean oraStatementCachingAvailable;
+    protected boolean oraRowPrefetchAvailable;
+    protected boolean oraLobHandlingAvailable;
+    protected boolean oraBatchAvailable;
 
+    protected static Map m_batchStatementsInProgress = Collections.synchronizedMap(new WeakHashMap());
+    /**
+     * Size of Oracle's native batch handling size.
+     */
+    protected Object[] paramStatementBatchSize;
     /**
      * Number of cached statements per connection,
      * when using implicit caching with OracleConnections.
@@ -75,7 +120,7 @@
      * @see <a href="http://www.apache.org/~mkalen/ojb/broker-tests.html">Profiling page</a>
      * for a discussion re sizing
      */
-    protected static final int STATEMENT_CACHE_SIZE = 10;
+    protected Object[] paramStatementCacheSize;
     /**
      * Number of rows pre-fetched by the JDBC-driver for each executed query,
      * when using Oracle row pre-fetching with OracleConnections.
@@ -85,43 +130,7 @@
      * connection-pool attribute with name="jdbc.defaultRowPrefetch".
      * Oracle JDBC-driver default value=10.
      */
-    protected static final int ROW_PREFETCH_SIZE = 20;
-
-    // From Oracle9i JDBC Developer's Guide and Reference:
-    // "Batch values between 5 and 30 tend to be the most effective."
-    protected static final int STATEMENTS_PER_BATCH = 20;
-    protected static Map m_batchStatementsInProgress = Collections.synchronizedMap(new WeakHashMap(STATEMENTS_PER_BATCH));
-
-    protected static final Class[] PARAM_TYPE_EMPTY = {};
-    protected static final Class[] PARAM_TYPE_INTEGER = {Integer.TYPE};
-    protected static final Class[] PARAM_TYPE_BOOLEAN = {Boolean.TYPE};
-    protected static final Class[] PARAM_TYPE_STRING = {String.class};
-
-    protected static final Object[] PARAM_EMPTY = new Object[]{};
-    protected static final Object[] PARAM_STATEMENT_CACHE_SIZE = new Object[]{new Integer(STATEMENT_CACHE_SIZE)};
-    protected static final Object[] PARAM_ROW_PREFETCH_SIZE = new Object[]{new Integer(ROW_PREFETCH_SIZE)};
-    protected static final Object[] PARAM_STATEMENT_BATCH_SIZE = new Object[]{new Integer(STATEMENTS_PER_BATCH)};
-    protected static final Object[] PARAM_BOOLEAN_TRUE = new Object[]{Boolean.TRUE};
-
-    protected static final String JBOSS_CONN_NAME =
-            "org.jboss.resource.adapter.jdbc.WrappedConnection";
-    protected static Class JBOSS_CONN_CLASS = null;
-
-    protected static Class ORA_CONN_CLASS;
-    protected static Class ORA_PS_CLASS;
-    protected static Class ORA_CLOB_CLASS;
-    protected static Class ORA_BLOB_CLASS;
-    protected static Class[] PARAM_TYPE_INT_ORACLOB;
-    protected static Class[] PARAM_TYPE_INT_ORABLOB;
-    protected static Method METHOD_SET_STATEMENT_CACHE_SIZE;
-    protected static Method METHOD_SET_IMPLICIT_CACHING_ENABLED;
-    protected static Method METHOD_SET_ROW_PREFETCH;
-    protected static Method METHOD_SET_BLOB = null;
-    protected static Method METHOD_SET_CLOB = null;
-    protected static boolean ORA_STATEMENT_CACHING_AVAILABLE;
-    protected static boolean ORA_ROW_PREFETCH_AVAILABLE;
-    protected static boolean ORA_CLOB_HANDLING_AVAILABLE;
-    protected static boolean ORA_BLOB_HANDLING_AVAILABLE;
+    protected Object[] paramRowPrefetchSize;
 
     /**
      * Helper to unwrap connections and statements.
@@ -129,97 +138,251 @@
     protected UnwrapHelper unwrapHelper;
 
 
-    /**
-     * Default constructor.
-     */
-    public PlatformOracle9iImpl()
+    public PlatformOracle9iImpl(JdbcConnectionDescriptor jcd)
     {
-        super();
+        super(jcd);
+        initOracleReflectedVars();
     }
 
     /**
-     * Enables Oracle statement caching and row prefetching if supported by the JDBC-driver.
-     * @param jcd the OJB <code>JdbcConnectionDescriptor</code> (metadata) for the connection to be initialized
-     * @param conn the <code>Connection</code>-object (physical) to be initialized
-     * @see PlatformDefaultImpl#initializeJdbcConnection
-     * @see <a href="http://otn.oracle.com/sample_code/tech/java/sqlj_jdbc/files/jdbc30/StmtCacheSample/Readme.html">
-     * Oracle TechNet Statement Caching Sample</a>
-     * @see <a href="http://otn.oracle.com/sample_code/tech/java/sqlj_jdbc/files/advanced/RowPrefetchSample/Readme.html">
-     * Oracle TechNet Row Pre-fetch Sample<a>
+     * Initializes static variables needed for Oracle-extensions and large BLOB/CLOB support,
+     * attributes set in {@link org.apache.ojb.broker.metadata.JdbcConnectionDescriptor}.
      */
-    public void initializeJdbcConnection(final JdbcConnectionDescriptor jcd,
-                                         final Connection conn)
-            throws PlatformException
+    private void initOracleReflectedVars()
     {
-        // Do all the generic initialization in PlatformDefaultImpl first
-        super.initializeJdbcConnection(jcd, conn);
+        unwrapHelper = new UnwrapHelper();
+        try
+        {
+            /*
+            Check for Oracle-specific classes, OracleConnection-specific
+            statement caching/row pre-fetch methods and Oracle BLOB/CLOB access methods.
+            We can do this in constructor in spite of possible mixing of instance being
+            able vs unable passed at runtime (since withouth these classes and methods
+            it's impossible to enable ORA-extensions at all even if instances are capable).
+            */
+            ORA_CONN_CLASS = ClassHelper.getClass(ORA_CONNECTION_CLASS_NAME, false);
+            ORA_PS_CLASS = ClassHelper.getClass(ORA_STATEMENT_CLASS_NAME, false);
+            /*
+            The unwrap pattern used in {@link org.apache.ojb.broker.util.UnwrapHelper}
+            to unwrap connection instance to Oracle's specific connection implementation class.
+            */
+            Object[] oracleUnwrapPattern = new Object[] {"oracle 10g", UnwrapHelper.TYPE_METHOD,
+                    new Class[]{ORA_CONN_CLASS}, "unwrapCompletely", null, null, null};
+            // add the oracle unwrap pattern
+            unwrapHelper.addUnwrapPattern(oracleUnwrapPattern);
+        }
+        catch(ClassNotFoundException e)
+        {
+            log.info("Can't access Oracle specific driver Connection/Statement classes", e);
+        }
+
 
-        // Check for managed environments known to reject Oracle extension at this level
-        // (saves us from trying to unwrap just to catch exceptions next)
-        final Class connClass = conn.getClass();
-        if (JBOSS_CONN_CLASS != null && JBOSS_CONN_CLASS.isAssignableFrom(connClass))
+        try
         {
-            if (logger.isDebugEnabled())
-            {
-                logger.debug("JBoss detected, Oracle Connection tuning left to J2EE container.");
-            }
-            return;
+            ORA_CLOB_CLASS = ClassHelper.getClass("oracle.sql.CLOB", false);
+            ORA_BLOB_CLASS = ClassHelper.getClass("oracle.sql.BLOB", false);
+            PARAM_TYPE_INT_ORACLOB = new Class[]{ Integer.TYPE, ORA_CLOB_CLASS };
+            PARAM_TYPE_INT_ORABLOB = new Class[]{ Integer.TYPE, ORA_BLOB_CLASS };
+            METHOD_SET_CLOB = ClassHelper.getMethod(ORA_PS_CLASS, "setCLOB", PARAM_TYPE_INT_ORACLOB);
+            METHOD_SET_BLOB = ClassHelper.getMethod(ORA_PS_CLASS, "setBLOB", PARAM_TYPE_INT_ORABLOB);
+        }
+        catch(ClassNotFoundException e)
+        {
+            log.info("Can't use Oracle specific BLOB/CLOB classes", e);
         }
 
-        // Check if this is a wrapped connection and if so unwrap it
-        final Connection oraConn = unwrapConnection(conn);
-        if (oraConn == null)
+        try
         {
-            return;
+            METHOD_SET_STATEMENT_CACHE_SIZE =
+                    ClassHelper.getMethod(ORA_CONN_CLASS, "setStatementCacheSize", PARAM_TYPE_INTEGER);
+            METHOD_SET_IMPLICIT_CACHING_ENABLED =
+                    ClassHelper.getMethod(ORA_CONN_CLASS, "setImplicitCachingEnabled", PARAM_TYPE_BOOLEAN);
         }
+        catch(Exception e)
+        {
+            log.info("Can't enable Oracle specific implicit statement caching", e);
+        }
+
 
-        // At this point we know that we have an OracleConnection instance and can thus
-        // try to invoke methods via reflection (if available)
-        if (ORA_STATEMENT_CACHING_AVAILABLE)
+        try
         {
-            try
+            METHOD_SET_ROW_PREFETCH = ClassHelper.getMethod(ORA_CONN_CLASS, "setDefaultRowPrefetch", PARAM_TYPE_INTEGER);
+        }
+        catch(Exception e)
+        {
+            log.info("Can't use Oracle specific row prefetch settings", e);
+        }
+
+        oraStatementCachingAvailable = METHOD_SET_STATEMENT_CACHE_SIZE != null && METHOD_SET_IMPLICIT_CACHING_ENABLED != null;
+        oraRowPrefetchAvailable = METHOD_SET_ROW_PREFETCH != null;
+        oraLobHandlingAvailable = METHOD_SET_CLOB != null && METHOD_SET_BLOB != null;
+
+        if(oraStatementCachingAvailable)
+        {
+            String stmtCacheSize = jcd.getAttribute(ATTRIBUTE_STATEMENT_CACHE_SIZE);
+            boolean enabled = false;
+            if(stmtCacheSize != null && stmtCacheSize.length() > 0)
             {
-                // Set number of cached statements and enable implicit caching
-                METHOD_SET_STATEMENT_CACHE_SIZE.invoke(oraConn, PARAM_STATEMENT_CACHE_SIZE);
-                METHOD_SET_IMPLICIT_CACHING_ENABLED.invoke(oraConn, PARAM_BOOLEAN_TRUE);
+                try
+                {
+                    Integer size = ConvertHelper.toInteger(stmtCacheSize);
+                    if(size.intValue() > 0)
+                    {
+                        paramStatementCacheSize = new Object[]{size};
+                        enabled = true;
+                    }
+                }
+                catch(NumberFormatException e)
+                {
+                    log.error("Can't enable Oracle's statement caching, illegal value for attribute: "
+                            + ATTRIBUTE_STATEMENT_CACHE_SIZE + "=" + stmtCacheSize);
+                }
             }
-            catch (Exception e)
+            if(!enabled)
+            {
+                oraStatementCachingAvailable = false;
+                log.info("Oracle's statement caching not used: "+ ATTRIBUTE_STATEMENT_CACHE_SIZE + "=" + stmtCacheSize);
+            }
+            else
+            {
+                log.info("Prepared to use Oracle's statement caching: "+ ATTRIBUTE_STATEMENT_CACHE_SIZE + "=" + stmtCacheSize);
+            }
+        }
+
+        if(oraRowPrefetchAvailable)
+        {
+            String prefetchSize = jcd.getAttribute(ATTRIBUTE_PREFETCH_SIZE);
+            boolean enabled = false;
+            if(prefetchSize != null && prefetchSize.length() > 0)
             {
-                if (logger.isDebugEnabled())
+                try
+                {
+                    Integer size = ConvertHelper.toInteger(prefetchSize);
+                    if(size.intValue() > 0)
+                    {
+                        paramRowPrefetchSize = new Object[]{size};
+                        enabled = true;
+                    }
+                }
+                catch(NumberFormatException e)
                 {
-                    logger.debug("PlatformOracle9iImpl could not enable Oracle statement caching."
-                                 + " Original/unwrapped connection classes="
-                                 + connClass.getName() + "/" + oraConn.getClass().getName());
+                    log.error("Can't enable Oracle's row prefetching, illegal value for attribute: "
+                            + ATTRIBUTE_PREFETCH_SIZE + "=" + prefetchSize);
                 }
             }
+            if(!enabled)
+            {
+                oraRowPrefetchAvailable = false;
+                log.info("Oracle's row prefetching not used: " + ATTRIBUTE_PREFETCH_SIZE + "=" + prefetchSize);
+            }
+            else
+            {
+                log.info("Prepared to use Oracle's row prefetching: " + ATTRIBUTE_PREFETCH_SIZE + "=" + prefetchSize);
+            }
         }
 
-        /*
-        mkalen: Note from the Oracle documentation:
-            Do not mix the JDBC 2.0 fetch size API and the Oracle row prefetching API
-            in your application. You can use one or the other, but not both.
-        */
-        final ConnectionPoolDescriptor cpd = jcd.getConnectionPoolDescriptor();
-        final int cpdFetchSizeHint = cpd.getFetchSize();
-        if (cpdFetchSizeHint == 0 && ORA_ROW_PREFETCH_AVAILABLE)
+        String batchSize = jcd.getAttribute(ATTRIBUTE_BATCH_SIZE);
+        boolean enabled = false;
+        if(batchSize != null && batchSize.length() > 0)
         {
             try
             {
-                final String prefetchFromJcd;
-                prefetchFromJcd = cpd.getJdbcProperties().getProperty("defaultRowPrefetch");
-                if (prefetchFromJcd == null)
+                Integer size = ConvertHelper.toInteger(batchSize);
+                if(size.intValue() > 0)
                 {
-                    METHOD_SET_ROW_PREFETCH.invoke(oraConn, PARAM_ROW_PREFETCH_SIZE);
+                    paramStatementBatchSize = new Object[]{size};
+                    enabled = true;
                 }
-                // Else, number of prefetched rows were set via Properties on Connection
             }
-            catch (Exception e)
+            catch(NumberFormatException e)
             {
-                if (logger.isDebugEnabled())
+                log.error("Can't enable Oracle's native batching, illegal value for attribute: "
+                        + ATTRIBUTE_BATCH_SIZE + "=" + batchSize);
+            }
+        }
+        if(!enabled)
+        {
+            oraBatchAvailable = false;
+            log.info("Oracle's native batching not used: " + ATTRIBUTE_BATCH_SIZE + "=" + batchSize);
+        }
+        else
+        {
+            log.info("Prepared to use Oracle's native batching: " + ATTRIBUTE_BATCH_SIZE + "=" + batchSize);
+        }
+    }
+
+    /**
+     * Enables Oracle statement caching and row prefetching if supported by the JDBC-driver.
+     * @param conn the <code>Connection</code>-object (physical) to be initialized
+     * @see PlatformDefaultImpl#initializeJdbcConnection
+     * @see <a href="http://otn.oracle.com/sample_code/tech/java/sqlj_jdbc/files/jdbc30/StmtCacheSample/Readme.html">
+     * Oracle TechNet Statement Caching Sample</a>
+     * @see <a href="http://otn.oracle.com/sample_code/tech/java/sqlj_jdbc/files/advanced/RowPrefetchSample/Readme.html">
+     * Oracle TechNet Row Pre-fetch Sample<a>
+     */
+    public void initializeJdbcConnection(final Connection conn) throws PlatformException
+    {
+        // Do all the generic initialization in PlatformDefaultImpl first
+        super.initializeJdbcConnection(conn);
+
+        Connection oraConn = null;
+        if(oraStatementCachingAvailable || oraRowPrefetchAvailable)
+        {
+            oraConn = unwrapConnection(conn);
+        }
+        if(oraConn != null)
+        {
+            final Class connClass = conn.getClass();
+            if(oraRowPrefetchAvailable)
+            {
+                /*
+                mkalen: Note from the Oracle documentation:
+                Do not mix the JDBC 2.0 fetch size API and the Oracle row prefetching API
+                in your application. You can use one or the other, but not both.
+                */
+                final ConnectionPoolDescriptor cpd = jcd.getConnectionPoolDescriptor();
+                if (cpd.getFetchSize() == 0)
                 {
-                    logger.debug("PlatformOracle9iImpl could not enable Oracle row pre-fetching."
-                                 + "Original/unwrapped connection classes="
-                                 + connClass.getName() + "/" + oraConn.getClass().getName());
+                    try
+                    {
+                        final String prefetchFromJcd = cpd.getJdbcProperties().getProperty("defaultRowPrefetch");
+                        if (prefetchFromJcd == null)
+                        {
+                            METHOD_SET_ROW_PREFETCH.invoke(oraConn, paramRowPrefetchSize);
+                            if(log.isDebugEnabled()) log.debug("Oracle's native row prefetching enabled for connection " + conn);
+                        }
+                        // Else, number of prefetched rows were set via Properties on Connection
+                    }
+                    catch (Exception e)
+                    {
+                        if (log.isDebugEnabled())
+                        {
+                            log.debug("PlatformOracle9iImpl could not enable Oracle row pre-fetching."
+                                         + "Original/unwrapped connection classes="
+                                         + connClass.getName() + "/" + oraConn.getClass().getName(), e);
+                        }
+                    }
+                }
+            }
+            if(oraStatementCachingAvailable)
+            {
+                // At this point we know that we have an OracleConnection instance and can thus
+                // try to invoke methods via reflection (if available)
+                try
+                {
+                    // Set number of cached statements and enable implicit caching
+                    METHOD_SET_STATEMENT_CACHE_SIZE.invoke(oraConn, paramStatementCacheSize);
+                    METHOD_SET_IMPLICIT_CACHING_ENABLED.invoke(oraConn, PARAM_BOOLEAN_TRUE);
+                    if(log.isDebugEnabled()) log.debug("Oracle's native implicit statement caching enabled for connection " + conn);
+                }
+                catch (Exception e)
+                {
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("PlatformOracle9iImpl could not enable Oracle statement caching."
+                                     + " Original/unwrapped connection classes="
+                                     + connClass.getName() + "/" + oraConn.getClass().getName());
+                    }
                 }
             }
         }
@@ -246,24 +409,29 @@
      */
     public void beforeBatch(PreparedStatement stmt) throws PlatformException
     {
-        // Check for Oracle batching support
-        final Method methodSetExecuteBatch;
-        final Method methodSendBatch;
-        methodSetExecuteBatch = ClassHelper.getMethod(stmt, "setExecuteBatch", PARAM_TYPE_INTEGER);
-        methodSendBatch = ClassHelper.getMethod(stmt, "sendBatch", null);
-
-        final boolean statementBatchingSupported = methodSetExecuteBatch != null && methodSendBatch != null;
-        if (statementBatchingSupported)
+        if (oraBatchAvailable)
         {
-            try
+            // Check for Oracle batching support
+            final Method methodSetExecuteBatch;
+            final Method methodSendBatch;
+            methodSetExecuteBatch = ClassHelper.getMethod(stmt, "setExecuteBatch", PARAM_TYPE_INTEGER);
+            methodSendBatch = ClassHelper.getMethod(stmt, "sendBatch", null);
+            if(methodSetExecuteBatch != null && methodSendBatch != null)
             {
-                // Set number of statements per batch
-                methodSetExecuteBatch.invoke(stmt, PARAM_STATEMENT_BATCH_SIZE);
-                m_batchStatementsInProgress.put(stmt, methodSendBatch);
+                try
+                {
+                    // Set number of statements per batch
+                    methodSetExecuteBatch.invoke(stmt, paramStatementBatchSize);
+                    m_batchStatementsInProgress.put(stmt, methodSendBatch);
+                }
+                catch (Exception e)
+                {
+                    throw new PlatformException(e.getLocalizedMessage(), e);
+                }
             }
-            catch (Exception e)
+            else
             {
-                throw new PlatformException(e.getLocalizedMessage(), e);
+                super.beforeBatch(stmt);
             }
         }
         else
@@ -281,8 +449,7 @@
     public void addBatch(PreparedStatement stmt) throws PlatformException
     {
         // Check for Oracle batching support
-        final boolean statementBatchingSupported = m_batchStatementsInProgress.containsKey(stmt);
-        if (statementBatchingSupported)
+        if (m_batchStatementsInProgress.containsKey(stmt))
         {
             try
             {
@@ -325,6 +492,8 @@
             }
             catch (Exception e)
             {
+                log.error("Error when invoke batch statement", e);
+                e = (Exception) ExceptionUtils.getRootCause(e);
                 throw new PlatformException(e.getLocalizedMessage(), e);
             }
         }
@@ -346,9 +515,7 @@
         {
             oraStmt = unwrapStatement(ps);
             oraConn = unwrapConnection(ps.getConnection());
-            oraLargeLobSupportAvailable =
-                    oraStmt != null && oraConn != null &&
-                    (sqlType == Types.CLOB ? ORA_CLOB_HANDLING_AVAILABLE : ORA_BLOB_HANDLING_AVAILABLE);
+            oraLargeLobSupportAvailable = oraStmt != null && oraConn != null && oraLobHandlingAvailable;
         }
         else
         {
@@ -365,20 +532,6 @@
             super.changePreparedStatementResultSetType(ps);
             ps.setBinaryStream(index, inputStream, buf.length);
         }
-        else if (value instanceof Double)
-        {
-            // workaround for the bug in Oracle thin driver
-            ps.setDouble(index, ((Double) value).doubleValue());
-        }
-        else if (sqlType == Types.BIGINT && value instanceof Integer)
-        {
-            // workaround: Oracle thin driver problem when expecting long
-            ps.setLong(index, ((Integer) value).intValue());
-        }
-        else if (sqlType == Types.INTEGER && value instanceof Long)
-        {
-            ps.setLong(index, ((Long) value).longValue());
-        }
         else if (sqlType == Types.CLOB && oraLargeLobSupportAvailable && value instanceof String)
         {
             // TODO: If using Oracle update batching with the thin driver, throw exception on 4k limit
@@ -427,20 +580,24 @@
      * @param conn the connection to unwrap (if needed)
      * @return OracleConnection or null if not able to unwrap
      */
-    protected Connection unwrapConnection(Connection conn)
+    protected Connection unwrapConnection(final Connection conn)
     {
-        final Connection unwrapped = unwrapHelper.unwrapConnection(ORA_CONN_CLASS, conn);
-        if (unwrapped == null)
+        Connection result = conn;
+        if(conn != null)
         {
-            // mkalen:  only log this as debug since it will be logged for every connection
-            //          (ie only useful during development).
-            if (logger.isDebugEnabled())
+            result = unwrapHelper.unwrapConnection(ORA_CONN_CLASS, conn);
+            if (result == null)
             {
-                logger.debug("PlatformOracle9iImpl could not unwrap " + conn.getClass().getName() +
-                             ", Oracle-extensions disabled.");
+                // mkalen:  only log this as debug since it will be logged for every connection
+                //          (ie only useful during development).
+                if (log.isDebugEnabled())
+                {
+                    log.debug("PlatformOracle9iImpl could not unwrap connection: " + conn.getClass() +
+                                 ", can't use Oracle's native Connection extensions.");
+                }
             }
         }
-        return unwrapped;
+        return result;
     }
 
     /**
@@ -448,81 +605,23 @@
      * @param ps the PreparedStatement to unwrap (if needed)
      * @return OraclePreparedStatement or null if not able to unwrap
      */
-    protected Statement unwrapStatement(Statement ps)
+    protected Statement unwrapStatement(final Statement ps)
     {
-        final Statement unwrapped = unwrapHelper.unwrapStatement(ORA_PS_CLASS, ps);
-        if (unwrapped == null)
+        Statement result = ps;
+        if(ps != null)
         {
-            // mkalen:  only log this as debug since it will be logged for every connection
-            //          (ie only useful during development).
-            if (logger.isDebugEnabled())
+            result = unwrapHelper.unwrapStatement(ORA_PS_CLASS, ps);
+            if (result == null)
             {
-                logger.debug("PlatformOracle9iImpl could not unwrap " + ps.getClass().getName() +
-                             ", large CLOB/BLOB support disabled.");
+                // mkalen:  only log this as debug since it will be logged for every connection
+                //          (ie only useful during development).
+                if (log.isDebugEnabled())
+                {
+                    log.debug("PlatformOracle9iImpl could not unwrap statement: " + ps.getClass() +
+                                 ", can't use Oracle's native Statement extensions.");
+                }
             }
         }
-        return unwrapped;
+        return result;
     }
-
-    /**
-     * Initializes static variables needed for Oracle-extensions and large BLOB/CLOB support.
-     */
-    protected void initOracleReflectedVars()
-    {
-        super.initOracleReflectedVars();
-        try
-        {
-            /*
-            Check for Oracle-specific classes, OracleConnection-specific
-            statement caching/row pre-fetch methods and Oracle BLOB/CLOB access methods.
-            We can do this in constructor in spite of possible mixing of instance being
-            able vs unable passed at runtime (since withouth these classes and methods
-            it's impossible to enable ORA-extensions at all even if instances are capable).
-            */
-            ORA_CONN_CLASS = ClassHelper.getClass("oracle.jdbc.OracleConnection", false);
-            ORA_PS_CLASS = ClassHelper.getClass("oracle.jdbc.OraclePreparedStatement", false);
-            ORA_CLOB_CLASS = ClassHelper.getClass("oracle.sql.CLOB", false);
-            ORA_BLOB_CLASS = ClassHelper.getClass("oracle.sql.BLOB", false);
-            PARAM_TYPE_INT_ORACLOB = new Class[]{ Integer.TYPE, ORA_CLOB_CLASS };
-            PARAM_TYPE_INT_ORABLOB = new Class[]{ Integer.TYPE, ORA_BLOB_CLASS };
-
-            /*
-            The unwrap pattern used in {@link org.apache.ojb.broker.util.UnwrapHelper}
-            to unwrap connection instance to Oracle's specific connection implementation class.
-            */
-            Object[] oracleUnwrapPattern = new Object[] {"oracle 10g", UnwrapHelper.TYPE_METHOD,
-                    new Class[]{ORA_CONN_CLASS}, "unwrapCompletely", null, null, null};
-            unwrapHelper = new UnwrapHelper();
-            // add the oracle unwrap pattern
-            unwrapHelper.addUnwrapPattern(oracleUnwrapPattern);
-
-            METHOD_SET_STATEMENT_CACHE_SIZE =
-                    ClassHelper.getMethod(ORA_CONN_CLASS, "setStatementCacheSize", PARAM_TYPE_INTEGER);
-            METHOD_SET_IMPLICIT_CACHING_ENABLED =
-                    ClassHelper.getMethod(ORA_CONN_CLASS, "setImplicitCachingEnabled", PARAM_TYPE_BOOLEAN);
-            METHOD_SET_ROW_PREFETCH = ClassHelper.getMethod(ORA_CONN_CLASS, "setDefaultRowPrefetch", PARAM_TYPE_INTEGER);
-            METHOD_SET_CLOB = ClassHelper.getMethod(ORA_PS_CLASS, "setCLOB", PARAM_TYPE_INT_ORACLOB);
-            METHOD_SET_BLOB = ClassHelper.getMethod(ORA_PS_CLASS, "setBLOB", PARAM_TYPE_INT_ORABLOB);
-
-            ORA_STATEMENT_CACHING_AVAILABLE =
-                    METHOD_SET_STATEMENT_CACHE_SIZE != null && METHOD_SET_IMPLICIT_CACHING_ENABLED != null;
-            ORA_ROW_PREFETCH_AVAILABLE = METHOD_SET_ROW_PREFETCH != null;
-            ORA_CLOB_HANDLING_AVAILABLE = METHOD_SET_CLOB != null;
-            ORA_BLOB_HANDLING_AVAILABLE = METHOD_SET_BLOB != null;
-        }
-        catch (ClassNotFoundException e)
-        {
-            // ignore (we tried...)
-        }
-        // Isolated checks for other connection classes (OK when not found)
-        try
-        {
-            JBOSS_CONN_CLASS = ClassHelper.getClass(JBOSS_CONN_NAME, false);
-        }
-        catch (ClassNotFoundException e)
-        {
-            // ignore (no problem)
-        }
-    }
-
 }

Modified: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracleImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracleImpl.java?view=diff&rev=489836&r1=489835&r2=489836
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracleImpl.java (original)
+++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/platforms/PlatformOracleImpl.java Fri Dec 22 18:40:42 2006
@@ -19,11 +19,16 @@
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 import org.apache.ojb.broker.util.ClassHelper;
 import org.apache.ojb.broker.util.sequence.SequenceManagerHelper;
+import org.apache.ojb.broker.metadata.FieldDescriptor;
+import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
+import org.apache.ojb.broker.PersistenceBrokerSQLException;
+import org.apache.commons.lang.SerializationUtils;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.StringReader;
+import java.io.Serializable;
 import java.lang.reflect.Field;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -34,6 +39,7 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.Types;
+import java.sql.Blob;
 import java.util.Properties;
 
 /**
@@ -128,36 +134,55 @@
  * </tr>
  * </table>
  *
- * @author <a href="mailto:[email protected]">Thomas Mahler <a>
  * @version $Id$
  */
 
 public class PlatformOracleImpl extends PlatformDefaultImpl
 {
     protected static final String THIN_URL_PREFIX = "jdbc:oracle:thin";
-    // Oracle:thin handles direct BLOB insert <= 4000 and update <= 2000
-    protected static final int THIN_BLOB_MAX_SIZE = 2000;
-    // Oracle:thin handles direct CLOB insert and update <= 4000
-    protected static final int THIN_CLOB_MAX_SIZE = 4000;
 
     /**
      * Field value of <code>oracle.jdbc.OracleTypes.CURSOR</code>.
      * @see #initOracleReflectedVars
      */
-    protected static int ORACLE_JDBC_TYPE_CURSOR = -10;
+    protected int ORACLE_JDBC_TYPE_CURSOR = -10;
 
     private Logger logger = LoggerFactory.getLogger(PlatformOracleImpl.class);
 
+    public PlatformOracleImpl(JdbcConnectionDescriptor jcd)
+    {
+        super(jcd);
+        initOracleReflectedVars();
+    }
+
     /**
-     * Default constructor.
+     * Initializes static variables needed for getting Oracle-specific JDBC types.
      */
-    public PlatformOracleImpl()
+    private void initOracleReflectedVars()
     {
-        initOracleReflectedVars();
+        try
+        {
+            // Check for Oracle-specific Types class
+            final Class oracleTypes = ClassHelper.getClass("oracle.jdbc.OracleTypes", false);
+            final Field cursorField = oracleTypes.getField("CURSOR");
+            ORACLE_JDBC_TYPE_CURSOR = cursorField.getInt(null);
+        }
+        catch (ClassNotFoundException e)
+        {
+            log.warn("PlatformOracleImpl could not find Oracle JDBC classes");
+        }
+        catch (NoSuchFieldException e)
+        {
+            log.warn("PlatformOracleImpl could not find Oracle JDBC type fields");
+        }
+        catch (IllegalAccessException e)
+        {
+            log.warn("PlatformOracleImpl could not get Oracle JDBC type values");
+        }
     }
 
     /**
-     * Method prepareNextValProcedureStatement implementation 
+     * Method prepareNextValProcedureStatement implementation
      * is simply copied over from PlatformMsSQLServerImpl class.
      * @see org.apache.ojb.broker.platforms.Platform#prepareNextValProcedureStatement(java.sql.Connection, java.lang.String, java.lang.String)
      */
@@ -198,25 +223,22 @@
      * all cases it's better to use setBinaryStream. Oracle also requires a change in the resultset
      * type of the prepared statement. MBAIRD NOTE: BLOBS may not work with Oracle database/thin
      * driver versions prior to 8.1.6.
-     * 
+     *
      * @see Platform#setObjectForStatement
      */
     public void setObjectForStatement(PreparedStatement ps, int index, Object value, int sqlType)
             throws SQLException
     {
-        if (((sqlType == Types.VARBINARY) || (sqlType == Types.LONGVARBINARY) || (sqlType == Types.BLOB))
-                && (value instanceof byte[]))
+        if ((sqlType == Types.VARCHAR || sqlType == Types.CHAR) && (value instanceof String || value instanceof Character))
         {
-            byte buf[] = (byte[]) value;
-            int length = buf.length;
-            if (isUsingOracleThinDriver(ps.getConnection()) && length > THIN_BLOB_MAX_SIZE)
-            {
-                throw new SQLException(
-                        "Oracle thin driver cannot update BLOB values with length>2000. (Consider using Oracle9i as OJB platform.)");
-            }
-            ByteArrayInputStream inputStream = new ByteArrayInputStream(buf);
-            changePreparedStatementResultSetType(ps);
-            ps.setBinaryStream(index, inputStream, length);
+            if (value instanceof String)
+            {
+                ps.setString(index, (String) value);
+            }
+            else // assert: value instanceof Character
+            {
+                ps.setString(index, value.toString());
+            }
         }
         else if (value instanceof Double)
         {
@@ -254,29 +276,55 @@
                 reader = new InputStreamReader(inputStream);
                 length = buf.length;
             }
-            if (isUsingOracleThinDriver(ps.getConnection()) && length > THIN_CLOB_MAX_SIZE)
-            {
-                throw new SQLException(
-                        "Oracle thin driver cannot insert CLOB values with length>4000. (Consider using Oracle9i as OJB platform.)");
-            }
             ps.setCharacterStream(index, reader, length);
         }
-        else if ((sqlType == Types.CHAR || sqlType == Types.VARCHAR)
-                 &&
-                 (value instanceof String || value instanceof Character))
+        else if ((value instanceof byte[]) && ((sqlType == Types.VARBINARY) || (sqlType == Types.LONGVARBINARY) || (sqlType == Types.BLOB)))
         {
-            if (value instanceof String)
+//            byte buf[] = (byte[]) value;
+//            int length = buf.length;
+//            ByteArrayInputStream inputStream = new ByteArrayInputStream(buf);
+//            // arminw: seems this no longer mandatory
+//            //changePreparedStatementResultSetType(ps);
+//            ps.setBinaryStream(index, inputStream, length);
+            ps.setBytes(index, (byte[]) value);
+        }
+        else if(sqlType == Types.JAVA_OBJECT)
+        {
+            // JAVA_OBJECT is not proper supported, workaround: use BLOB type
+            byte[] ser = SerializationUtils.serialize((Serializable) value);
+            ps.setBytes(index, ser);
+        }
+        else
+        {
+            super.setObjectForStatement(ps, index, value, sqlType);
+        }
+    }
+
+    public Object postPrepareReadInValue(final FieldDescriptor fld, final Object value)
+    {
+        /*
+        workaround for JAVA_OBJECT type. Currently Oracle doesn't
+        proper support JAVA_OBJECT type. On insert we transform JAVA_OBJECT
+        to byte[] array, thus on read we have to deserialize. The mapping type
+        is BLOB.
+        */
+        if(fld.getJdbcType().getType() == Types.JAVA_OBJECT && value instanceof Blob)
+        {
+            Blob ret = (Blob) value;
+            byte[] b;
+            try
             {
-                ps.setString(index, (String) value);
+                b = ret.getBytes(1, (int) ret.length());
             }
-            else // assert: value instanceof Character
+            catch(SQLException e)
             {
-                ps.setString(index, value.toString());
+                throw new PersistenceBrokerSQLException("Can't read Blob object of serialized JAVA_OBJECT type", e);
             }
+            return SerializationUtils.deserialize(b);
         }
         else
         {
-            super.setObjectForStatement(ps, index, value, sqlType);
+            return super.postPrepareReadInValue(fld, value);
         }
     }
 
@@ -314,6 +362,11 @@
         return ORACLE_JOIN_SYNTAX;
     }
 
+    public boolean supportsOrderByInSubSelect()
+    {
+        return false;
+    }
+
     public String createSequenceQuery(String sequenceName)
     {
         return "CREATE SEQUENCE " + sequenceName;
@@ -399,15 +452,14 @@
     /**
      * @see org.apache.ojb.broker.platforms.Platform#registerOutResultSet(java.sql.CallableStatement, int)
      */
-    public void registerOutResultSet(CallableStatement stmt, int position)
-            throws SQLException
+    public void registerOutResultSet(CallableStatement stmt, int position) throws SQLException
     {
         stmt.registerOutParameter(position, ORACLE_JDBC_TYPE_CURSOR);
     }
 
     /**
      * Checks if the supplied connection is using the Oracle thin driver.
-     * 
+     *
      * @param conn database connection for which to check JDBC-driver
      * @return <code>true</code> if the connection is using Oracle thin driver, <code>false</code>
      *         otherwise.
@@ -435,31 +487,4 @@
         }
         return false;
     }
-
-    /**
-     * Initializes static variables needed for getting Oracle-specific JDBC types.
-     */
-    protected void initOracleReflectedVars()
-    {
-        try
-        {
-            // Check for Oracle-specific Types class
-            final Class oracleTypes = ClassHelper.getClass("oracle.jdbc.OracleTypes", false);
-            final Field cursorField = oracleTypes.getField("CURSOR");
-            ORACLE_JDBC_TYPE_CURSOR = cursorField.getInt(null);
-        }
-        catch (ClassNotFoundException e)
-        {
-            log.warn("PlatformOracleImpl could not find Oracle JDBC classes");
-        }
-        catch (NoSuchFieldException e)
-        {
-            log.warn("PlatformOracleImpl could not find Oracle JDBC type fields");
-        }
-        catch (IllegalAccessException e)
-        {
-            log.warn("PlatformOracleImpl could not get Oracle JDBC type values");
-        }
-    }
-
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.