Calling Oracle Stored Procedure from Hibernate

While calling Oracle stored procedure from Hibernate  there is couple of rules that we need to follow. There can be only one return value and this must be a reference cursor. This return reference cusor must be the first and only out value for the stored procedure. It is required that stored procedure must return a reference cursor to be used from Hibernate.

Here is my stored procedure which return book name and ISBN number for a given branch and for a given author

CREATE OR REPLACE PROCEDURE SP_LIB_DTL(p_cursor    out sys_refcursor,
                                       in_brnch_cd in number,
                                       in_auth_cd in number)
as
  bookName varchar2(8);
  ISBN     number;
begin
  bookName := null;
  ISBN     := 0;
  open p_cursor for
    select l.book_name, l.isbn_nbr
      into bookName, ISBN
      from LIB_BRNCH_DTL l
     where l.branch_code = in_brnch_cd
     and l.auth_code = in_auth_cd;

end;

HIbernate Mapping for return class and Named Query:

<?xml version=”1.0″ encoding=”utf-8″?>
<!DOCTYPE hibernate-mapping PUBLIC “-//Hibernate/Hibernate Mapping DTD 3.0//EN”
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd“>
<hibernate-mapping>
<class name=”com.org.lib.LibraryDetails”>
<id name=”ISBN” type=”long” />
<property name=”bookName” type=”string” />
</class>
 <sql-query name=”LIB_SP” callable=”true”>
 <return class=”com.org.lib.LibraryDetails”>
   <return-property name=”ISBN” column=”isbn_nbr” />
   <return-property name=”bookName” column=”book_name” />
 </return>
  {  call SP_LIB_DTL(? , :branchCD ,:authorCD) }
 </sql-query>
</hibernate-mapping>

Make sure you have used the correct database field name value for the column attribute for the return property mapping. You will get the following error if you don’t map the correct databse field name

could not execute query; bad SQL grammar [{  call SP_LIB_DTL(? , ?) }];
nested exception is java.sql.SQLException: Invalid column name

Here is the DAO implementation for executing query and to set the bind parameter values.

public  List selectBooks(final BigDecimal branchCode,final BigDecimal authorCode){
        return (List) getHibernateTemplate().execute(new HibernateCallback() {
              public Object doInHibernate(Session session) throws HibernateException, SQLException
              {
                  Query q = session.getNamedQuery(”LIB_SP”);
                  q.setLong(”branchCD”, branchCode.longValue());
                  q.setLong(”authorCD”, authorCode.longValue());
                  return q.list();
              }
          });
      }

Comments

7 Responses to “Calling Oracle Stored Procedure from Hibernate”

  1. Gobi

    June 18th, 2009 9:35 pm

    Thank s for this post. I have another doubt. If i want to return a string frm the procedure how should i configure that in the hbm file?
    also how should i call in the java?

  2. Dhanya

    June 19th, 2009 8:14 am

    You need to open a cursor and return the cursor. Curosr can have String return out parameter in it. In the given example cursor has ‘bookName’ out parameter which is mapped to a property in the LibraryDetails class in the hibernate mapping. When you call the stored procedure you get a list of LibraryDetails object. Just need to iterate through the list and get LibraryDetails object values out of it. Hope this helps..

  3. Thiago Cavalieri da Silveira

    July 9th, 2009 2:28 pm

    I did call a stored procedure returning a cursor, but i can’t call a stored function returning a number for exemple.

    How can i do that?

    My hibernate maping:

    { ? = call PA_TIPO_LOCAL.INC_TIPO_LOCAL() }

    My java code:

    Query q = ManageDAO.getSession().getNamedQuery(”incTipoLocal”);

    q.uniqueResult();

    The Error:

    Hibernate:
    { ? = call PA_TIPO_LOCAL.INC_TIPO_LOCAL() }
    16:27:31,546 WARN JDBCExceptionReporter:100 – SQL Error: 6550, SQLState: 65000
    16:27:31,562 ERROR JDBCExceptionReporter:101 – ORA-06550: line 1, column 13:
    PLS-00382: expression is of wrong type
    ORA-06550: line 1, column 7:
    PL/SQL: Statement ignored

    Exception in thread “main” org.hibernate.exception.SQLGrammarException: could not execute query
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.loader.Loader.doList(Loader.java:2231)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)
    at org.hibernate.loader.Loader.list(Loader.java:2120)
    at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:312)
    at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1722)
    at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:165)
    at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:175)
    at org.hibernate.impl.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:835)
    at br.es.csi.cad.dao.TipoLocalDAO.incTipoLocal(TipoLocalDAO.java:30)
    at br.es.csi.cad.dao.TipoLocalDAO.main(TipoLocalDAO.java:38)
    Caused by: java.sql.SQLException: ORA-06550: line 1, column 13:
    PLS-00382: expression is of wrong type
    ORA-06550: line 1, column 7:
    PL/SQL: Statement ignored

    Can you help me, please?

    Thanks.

  4. Brian Bohl

    July 9th, 2009 5:12 pm

    Per the Hibernate Reference doc (http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/#sp_query)

    For Oracle the following rules apply:

    *A function must return a result set. The first parameter of a procedure must be an OUT that returns a result set. This is done by using a SYS_REFCURSOR type in Oracle 9 or 10. In Oracle you need to define a REF CURSOR type. See Oracle literature for further information.

  5. Pino

    October 23rd, 2009 5:21 am

    And what about a stored procedure that returns nothing? My stored proc has only input parameters. How can i confiugure and call it?

  6. Antony

    November 10th, 2009 1:12 pm

    calling storeprocedure which returns nothing.

    { call P_TEST.SP_UPDATE_TEST_USER(:id,:displayName) }

    ———————————————————————————-
    procedure sp_update_test_user(intId in integer, vchDisplayName in varchar2)is
    begin
    update test_user tu set tu.display_name=vchDisplayName where tu.id=intId;
    end sp_update_test_user;
    ——————————————————————————–
    public boolean updateUserDB(){
    Transaction tx = null;
    Session session = HibernateUtil.getInstance().getCurrentSession();
    try {
    System.out.println(”********** UpdateUserDB *************”);
    System.out.println(”id –> “+paramBean.getId());
    System.out.println(”DisplayName –> “+paramBean.getDisplayName());
    System.out.println(”*************************************”);
    tx = session.beginTransaction();
    Query query = session.getNamedQuery(”SP_UPDATE_TEST_USER”);
    query.setInteger(”id”, Integer.parseInt(”"+paramBean.getId()));
    query.setString(”displayName”, paramBean.getDisplayName());
    int retInt=query.executeUpdate();
    tx.commit();
    return true;
    } catch (RuntimeException e) {
    if (tx != null && tx.isActive()) {
    try {
    // Second try catch as the rollback could fail as well
    tx.rollback();
    } catch (HibernateException e1) {
    logger.debug(”Error rolling back transaction”);
    }
    // throw again the first exception
    throw e;
    }
    return false;
    }
    }
    ———————————————————————————–

    I hope this will help you.

  7. Dhanya

    November 10th, 2009 1:52 pm

    Pino,
    Try to define a REF CURSOR and return the number of rows affected by the insert/update/delete operation
    Hope this helps..

Leave a comment!