-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: Oracle CLOB and mysql compatibility?
PostPosted: Wed Sep 24, 2003 12:41 pm 
Beginner
Beginner

Joined: Wed Sep 10, 2003 5:34 pm
Posts: 36
Location: New York, NY
Hey all,

I'm working on a project that is being deployed to Oracle, but I'm developing locally on MySQL and I'd like to stay that way. However, I've now hit the need for a larger than 4000 character data element. In mysql this is no problem (TEXT type), in Oracle suddenly we're into CLOBs and all that other nasty stuff. If do what's necessary to switch the field to a CLOB, is that going to preclude me from working in MySQL anymore? Should I instead implement something as suggested in this thread: http://forum.hibernate.org/viewtopic.php?t=464

I'd like to avoid anything Oracle specific in the application, but I also don't want to introduce more complexity than I need.

Thanks for any advice,

Matt


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 25, 2003 9:23 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Have you read the page in the community area that discusses Oracle CLOBs?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 25, 2003 12:19 pm 
Beginner
Beginner

Joined: Wed Sep 10, 2003 5:34 pm
Posts: 36
Location: New York, NY
Yup, I took a look at that, and my question wasn't so much whether CLOBs were possible, but whether I could use them with both Oracle and MySQL with the same codebase. For example, hibernate seems to interpret a clob type as TEXT for mysql, but when I try to access it as a clob during execution on MySQL I get

Code:
com.mysql.jdbc.jdbc2.NotImplemented
   at com.mysql.jdbc.jdbc2.ResultSet.getClob(Unknown Source)


So when I try to use the TextType from the community pages, I get

Code:
com.mysql.jdbc.jdbc2.NotImplemented
   at com.mysql.jdbc.jdbc2.ResultSet.getCharacterStream(Unknown Source)


So I can't seem to make either work.

I was just wondering if there was a known solution to this, otherwise I'll try to work something out.

Thanks alot.

Matt


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 25, 2003 12:29 pm 
Beginner
Beginner

Joined: Wed Sep 10, 2003 5:34 pm
Posts: 36
Location: New York, NY
I do have something that feels slightly cheesey running now, I modified the get() method in the TextType to do something like

Code:
        Reader reader = null;
        try {
            reader = rs.getCharacterStream(name);
        } catch (SQLException e) {
            // This means we're on mysql and we should treat this like a string
            return rs.getString(name);
        }


So if it tosses an exception then I just try to get it as a String. Probably a better way to do this would involve some kind of metadata about the database in use, but for now I'm going to try this out.

Any advice, let me know. Thanks.

Matt


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 29, 2003 10:48 am 
Beginner
Beginner

Joined: Wed Sep 10, 2003 5:34 pm
Posts: 36
Location: New York, NY
In case anyone's interested, here is the current form of my solution to a datatype that is over 4000 characters and works seamlessly between Oracle and MySQL:

Code:
import java.io.*;
import java.sql.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Field;

import org.apache.commons.lang.ObjectUtils;
import net.sf.hibernate.type.ImmutableType;
import net.sf.hibernate.HibernateException;

public class TextType extends ImmutableType {

    /** Name of the oracle driver -- used to support Oracle clobs as a special case */
    private static final String ORACLE_DRIVER_NAME = "Oracle JDBC driver";

    /** Version of the oracle driver being supported with clob. */
    private static final int ORACLE_DRIVER_MAJOR_VERSION = 9;
    private static final int ORACLE_DRIVER_MINOR_VERSION = 0;

    public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
        Reader reader = null;
        try {
            reader = rs.getCharacterStream(name);
        } catch (SQLException e) {
            // This means we're on mysql and we should treat this like a string
            return rs.getString(name);
        }
        if (reader == null) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        try {
            char[] charbuf = new char[4096];
            for (int i = reader.read(charbuf); i > 0; i = reader.read(charbuf)) {
                sb.append(charbuf, 0, i);
            }
        } catch (IOException e) {
            throw new SQLException(e.getMessage());
        }
        return sb.toString();
    }

    public Class returnedClass() {
        return String.class;
    }

    public void set(PreparedStatement st, Object value, int index)
            throws SQLException {

        try {
            //StringReader r = new StringReader((String) value);
            //st.setCharacterStream(index, r, ((String) value).length());
            clobSet(st, value, index);
        } catch (SQLException e) {
            st.setString(index, (String) value);
        } catch (HibernateException he) {
            System.out.println(he);
        }
    }

    public void clobSet(PreparedStatement st, Object value, int index)
            throws HibernateException, SQLException {

        DatabaseMetaData dbMetaData = st.getConnection().getMetaData();
        if (value == null) {
            st.setNull(index, sqlType());
        } else if (ORACLE_DRIVER_NAME.equals(dbMetaData.getDriverName())) {
            if ((dbMetaData.getDriverMajorVersion() >= ORACLE_DRIVER_MAJOR_VERSION) &&
                    (dbMetaData.getDriverMinorVersion() >= ORACLE_DRIVER_MINOR_VERSION)) {
                try {
                    // Code compliments of Scott Miller
                    // support oracle clobs without requiring oracle libraries
                    // at compile time
                    // Note this assumes that if you are using the Oracle Driver.
                    // then you have access to the oracle.sql.CLOB class

                    // First get the oracle clob class
                    Class oracleClobClass = Class.forName("oracle.sql.CLOB");

                    // Get the oracle connection class for checking
                    Class oracleConnectionClass = Class.forName("oracle.jdbc.OracleConnection");

                    // now get the static factory method
                    Class partypes[] = new Class[3];
                    partypes[0] = Connection.class;
                    partypes[1] = Boolean.TYPE;
                    partypes[2] = Integer.TYPE;
                    Method createTemporaryMethod = oracleClobClass.getDeclaredMethod("createTemporary", partypes);
                    // now get ready to call the factory method
                    Field durationSessionField = oracleClobClass.getField("DURATION_SESSION");
                    Object arglist[] = new Object[3];
                    Connection conn = st.getConnection();

                    // Make sure connection object is right type
                    if (!oracleConnectionClass.isAssignableFrom(conn.getClass())) {
                        throw new HibernateException("JDBC connection object must be a oracle.jdbc.OracleConnection. " +
                                "Connection class is " + conn.getClass().getName());
                    }

                    arglist[0] = conn;
                    arglist[1] = Boolean.TRUE;
                    arglist[2] = durationSessionField.get(null); //null is valid because of static field

                    // Create our CLOB
                    Object tempClob = createTemporaryMethod.invoke(null, arglist); //null is valid because of static method

                    // get the open method
                    partypes = new Class[1];
                    partypes[0] = Integer.TYPE;
                    Method openMethod = oracleClobClass.getDeclaredMethod("open", partypes);

                    // prepare to call the method
                    Field modeReadWriteField = oracleClobClass.getField("MODE_READWRITE");
                    arglist = new Object[1];
                    arglist[0] = modeReadWriteField.get(null); //null is valid because of static field

                    // call open(CLOB.MODE_READWRITE);
                    openMethod.invoke(tempClob, arglist);

                    // get the getCharacterOutputStream method
                    Method getCharacterOutputStreamMethod = oracleClobClass.getDeclaredMethod("getCharacterOutputStream", null);

                    // call the getCharacterOutpitStream method
                    Writer tempClobWriter = (Writer) getCharacterOutputStreamMethod.invoke(tempClob, null);

                    // write the string to the clob
                    tempClobWriter.write((String) value);
                    tempClobWriter.flush();
                    tempClobWriter.close();

                    // get the close method
                    Method closeMethod = oracleClobClass.getDeclaredMethod("close", null);

                    // call the close method
                    closeMethod.invoke(tempClob, null);

                    // add the clob to the statement
                    st.setClob(index, (Clob) tempClob);
                } catch (ClassNotFoundException e) {
                    // could not find the class with reflection
                    throw new HibernateException("Unable to find a required class.\n" + e.getMessage());
                } catch (NoSuchMethodException e) {
                    // could not find the metho with reflection
                    throw new HibernateException("Unable to find a required method.\n" + e.getMessage());
                } catch (NoSuchFieldException e) {
                    // could not find the field with reflection
                    throw new HibernateException("Unable to find a required field.\n" + e.getMessage());
                } catch (IllegalAccessException e) {
                    throw new HibernateException("Unable to access a required method or field.\n" + e.getMessage());
                } catch (InvocationTargetException e) {
                    throw new HibernateException(e.getMessage());
                } catch (IOException e) {
                    throw new HibernateException(e.getMessage());
                }
            } else {
                throw new HibernateException("No CLOBS support. Use driver version " + ORACLE_DRIVER_MAJOR_VERSION +
                        ", minor " + ORACLE_DRIVER_MINOR_VERSION);
            }
        } else {
            String str = (String) value;
            StringReader r = new StringReader(str);
            st.setCharacterStream(index, r, str.length());
        }
    }

    public int sqlType() {
        return Types.CLOB;
    }

    public Class getReturnedClass() {
        return String.class;
    }

    public String getName() {
        return "string";
    }

    public boolean hasNiceEquals() {
        return false;
    }

    public boolean equals(Object x, Object y) {
        return ObjectUtils.equals(x, y);
    }

    public String toXML(Object value) {
        return (String) value;
    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 10, 2003 10:46 am 
Newbie

Joined: Fri Oct 10, 2003 9:53 am
Posts: 1
Hi

I've messed about with Oracle clobs before in other situations and noticed your example doesn't call freeTemporary() to release the temporary Oracle Clob that gets created on calls to createTemporary(). As it stands I'm pretty sure that you'll be leaking memory, as these temporary Clobs never get cleaned up.

The real gotcha is that I don't think you can call freeTemporary() until after the PreparedStatement has been executed. I'm new to Hibernate and so don't know enough about user types to know if there's an appropriate hook that can be used to ensure that freeTemporary() gets called after the statement execution.

I've also added a comment to the 'Using clobs with Oracle' document to this effect. Sorry I can't offer any form of solution or work around at this time.

Rob


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 20, 2007 6:50 am 
Newbie

Joined: Fri Jul 20, 2007 6:02 pm
Posts: 12
Hi,
Iam trying to manipulate Oracle CLOB columns with hibernate 3.1 and seeing this weird error. In my unit tester, I have test cases to create a record. In one, I populate the CLOB value in the object before persisting and in the other I do not populate the CLOB value in the object. If I run the test cases individually they all pass without any issues. However if I run consequtively, I get this error. What could be the reason?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.