5

I have a custom function in oracle returning a number after deleting records. I could get a value in sql_plus such as

call my_function(4) into :out_number;

where out_number is a variable defined as number.

I could verify out_number has a value when I do "PRINT OUT_NUMBER."

My question is how to call this function from JPA.

I've tried like

Query query = em.createNativeQuery("{call my_function(?)}");
query.serParameter(1, 4);
return query.executeUpdate();

and got an error basically my_function is not defined. How can I get a return value as in CALL...INTO on SQL_PLUS?

If this method is not desirable, can someone please recommend any suggestion? JPA is the only option for me at this moment. I could create a stored procedure but I'm not sure if I can get a return value from it since OUT parameters are not supported.

Thanks for your help in advance!

1
  • Tulskiy, I can't use 'select ... from dual' because my_function performs delete statements (DML). I have tried to use BEGIN my_function(?); END; but, I have no luck to get a return value. Commented Aug 9, 2011 at 13:10

5 Answers 5

2

I used this to execute native functions in oracle:

Query query = em.createNativeQuery("select my_function(:param) from dual");
query.setParameter("param", 4);
return query.getSingleResult();
Sign up to request clarification or add additional context in comments.

Comments

2

From https://vladmihalcea.com/how-to-call-oracle-stored-procedures-and-functions-from-hibernate/:

First, we can simply call the Oracle function just like any other SQL query:

BigDecimal commentCount = (BigDecimal) entityManager
    .createNativeQuery(
        "SELECT fn_count_comments(:postId) FROM DUAL"
    )
    .setParameter("postId", 1L)
    .getSingleResult();

Another approach is to call the database function using plain JDBC API:

Session session = entityManager.unwrap( Session.class );

final AtomicReference<Integer> commentCount = 
    new AtomicReference<>();

session.doWork( connection -> {
    try (CallableStatement function = connection
            .prepareCall(
                "{ ? = call fn_count_comments(?) }"
            )
        ) {
        function.registerOutParameter( 1, Types.INTEGER );
        function.setInt( 2, 1 );
        function.execute();
        commentCount.set( function.getInt( 1 ) );
    }
} );

Comments

1

When using Spring Data JPA / Spring JDBC you can use SimpleJdbcCall for calling functions and procedures.

For such function header:

FUNCTION get_text (p_param IN VARCHAR2) RETURN VARCHAR2

Use this call:

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

@Repository
public class MyRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public String callGetTextFunction(String param) {
        SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
                .withCatalogName("PKG_PACKAGE") //package name
                .withFunctionName("GET_TEXT"); //function name
        SqlParameterSource paramMap = new MapSqlParameterSource()
                .addValue("p_param", param));
        //First parameter is function output parameter type.
        return jdbcCall.executeFunction(String.class, paramMap));
    }

}

Comments

0

If you are using EclipseLink you can use a StoredFunctionCall object to call a stored function such as this.

You could also define it as a named query using the @NamedStoredFunctionQuery.

Comments

0

It's a quite old question but I have not found here the proper solution... Here is a code that works in my project:

    EntityManager em;
    String functionName = "NameOfStoredFunction";
    Map<String, Object> arguments = new LinkedHashMap();
    arguments.put("nameOfArgument", "value");
    StoredFunctionCall functionCall = new StoredFunctionCall();
    functionCall.setProcedureName(functionName);
    functionCall.setResult("RESULT", String.class);

    for(String key : arguments.keySet()){
        functionCall.addNamedArgumentValue(key, arguments.get(key));
    }

    ValueReadQuery valQuery = new ValueReadQuery();
    valQuery.setCall(functionCall);

    Query query = ((JpaEntityManager)em.getDelegate()).createQuery(valQuery);

    String call_result = (String)query.getSingleResult();

3 Comments

Above code works for functions that modify data in database (use DML statements).
I guess this is only relevant for EclipseLink.
From where do you get this StoredFunctionCall object?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.