8

I am running an simple application that uses Spring Boot + Spring Data JPA for persistence.

Below is a sample Oracle function I would like to have the value returned at the Service implementation class.

CREATE OR REPLACE PACKAGE PKG_TEST AS 
  FUNCTION HELLO_WORLD(TEXT VARCHAR2) RETURN VARCHAR2;
END PKG_TEST;

CREATE OR REPLACE PACKAGE BODY PKG_TEST AS 
  FUNCTION HELLO_WORLD(TEXT VARCHAR2) RETURN VARCHAR2 IS
  BEGIN
    RETURN 'HELLO WORLD ' || TEXT;
  END;
END PKG_TEST;

Doing this with no framework would be simple, but the project is built into Spring Boot JPA, so it's better to use it.

I need a reference guide link or simple base structure to follow. I searched all over SO and Spring Data JPA reference and all examples I found are for CRUD and Stored Procedures, nothing for Functions.

I tried to use the Stored procedure example modified for function but didn't work.

1
  • I don't think there is support for sql functions, there are ways to call them but not to create and store them as far as I know. The JPA specification hasn't such contract from the javadoc, I doubt it's being implemented by any persistence provider Commented Aug 24, 2017 at 17:27

6 Answers 6

16

You can call your function via native query and get result from dual.

public interface HelloWorldRepository extends JpaRepository<HelloWorld, Long> {

    @Query(nativeQuery = true, value = "SELECT PKG_TEST.HELLO_WORLD(:text) FROM dual")
    String callHelloWorld(@Param("text") String text);

}

Note that it won't work if your function is using DML statements. In this case you'll need to use @Modifying annotation over query, but then the function itself must return number due to @Modifying return type restrictions.

You can also implement your CustomRepository and use SimpleJdbcCall:

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 HelloWorldRepositoryImpl implements HelloWorldRepositoryCustom {

    @Autowired
    private JdbcTemplate jdbcTemplate;

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

}
Sign up to request clarification or add additional context in comments.

1 Comment

I cant propose an edit for a single character, but there is an extra ")" on your .addValue line.
1

Incase if you need to return a set of columns with n number of rows returned as a oracle type from a function, Use Table(function_name) with the select statement to parse the type as table and get as list of object array List.

@Query(nativeQuery = true, value = "SELECT * FROM TABLE(ListOfStates(:country))")
List<Object[]> findStatesByCountry(@Param("country") String country);

1 Comment

What happens to this query if the ListOfStates function also takes an OUT parameter (let say myOutParam) please ??
0

If you are using Hibernate as JPA Provider you may create custom dialect and register needed function.

public class CustomDialect extends Oracle10gDialect {
    public CustomDialect() {
        super();
        // CustomFunction implements SqlFunction
        registerFunction("custom_function", new CustomFunction());
        // or use StandardSQLFunction; useful for coalesce
        registerFunction("coalesce", new StandardSQLFunction("coalesce"));
    }
}

Comments

0

using entityManager.createNativeQuery works.

See: How to call a custom Oracle function returning a value from JPA

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

Comments

0
public interface inteface-name extends CrudRepository<Object,Long> {

    @Procedure(procedureName = "procedure-name", outputParameterName = "param-out-name")
    BigDecimal method-name(dataType input-param);
}

Comments

0
 this.entityManager.getSession().doWork(connection -> {
        try (CallableStatement query = connection
                .prepareCall("BEGIN ? := FUNCTION_NAME(?); END;")) {
            query.registerOutParameter("PARAM1", Types.VARCHAR); // out param
            query.setString("PARAM2"), "SOME_VALUE"); // in param
            query.execute();
            String value = query.getString("PARAM1"); //outparam result
            System.out.println(value);
        } catch (Exception ex) {
           //process exception here
        }
    });

Comments

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.