Calling a Oracle Function from JPA 2.1? - java

Im trying to call an oracle function from JPA 2.1 and am getting this error -
org.hibernate.exception.GenericJDBCException: could not extract ResultSet
...
Caused by: java.sql.SQLException: Missing IN or OUT parameter at index:: 6
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
...
The function is defined -
FUNCTION my_function (
username IN VARCHAR2,
case_number IN NUMBER,
event_type_id IN NUMBER,
arguments IN VARCHAR2,
note IN VARCHAR2
)
RETURN NUMBER
IS
retval NUMBER;
BEGIN
-- WORKING OF FUNCTION REMOVED
retval := 1;
RETURN retval;
END;
And I am calling this through -
#NamedNativeQuery(
name="my_function",query="{ call proc_history.create_parent_event(:username, :caseNumber, :eventTypeId, :arguments, :note) }"
)
public class MyJPAObject {
//
}
With my DAO -
public Integer callMyFuntion() {
Query query = em.createNamedQuery("my_function");
query.setParameter("username", "me");
query.setParameter("caseNumber", 123456);
query.setParameter("eventTypeId", 123);
query.setParameter("arguments", "test");
query.setParameter("note", "test");
return (Integer)query.getSingleResult();
}
Ive confirmed I can call the function using -
DECLARE retval NUMBER;
BEGIN retval := my_function('me', 123456, 123, 'test', 'test');
END;
What do I need to do to call this through JPA?

If the functions returns data, it should be like this:
query = "{ ? = call proc_history.create_parent_event(:username, :caseNumber, :eventTypeId, :arguments, :note) }"

Related

#NamedStoredProcedureQuery is not working for the simple procedure call in JPA Java

I am getting an error : Attempt to set a parameter name that does not occur in the SQL: i_reorg_id . It does not make sense to me as there is i_reorg_id in the SQL.
Procedure is:
create or replace PROCEDURE PRINTREORGID(i_reorg_id IN VARCHAR2, o_reorg_id OUT VARCHAR2)
AS BEGIN
SELECT reorg_id
INTO o_reorg_id
FROM reorg_automation_workflowinput
WHERE reorg_id = i_reorg_id;
END;
Entity is:
#Entity
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(name = "fetchProcedure", procedureName = "PRINTREORGID", parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, type = String.class, name = "i_reorg_id"),
#StoredProcedureParameter(type = String.class, mode = ParameterMode.OUT, name = "o_reorg_id"),
})
})
And Repository is:
#Procedure(name = "fetchProcedure", procedureName="PRINTREORGID")
String reorgAutomationWorkFlow(#Param("i_reorg_id") String i_reorg_id);
You can call the procedure another way(This is Best Practice):-
Procedure:-
procedure getEmployeeById(
id_in IN EMPLOYEE.ID%type,
e_disp OUT SYS_REFCURSOR
) IS
hasEmployee number;
BEGIN
hasEmployee := 0;
SELECT count(*) into hasEmployee from EMPLOYEE where ID = id_in;
IF hasEmployee <> 0 THEN --here <> means !=
OPEN e_disp FOR SELECT * FROM EMPLOYEE WHERE ID = id_in;
ELSE
--return empty SYS_REFCURSOR couse 1=2 not equal always
OPEN e_disp FOR SELECT * FROM EMPLOYEE WHERE 1=2;
END IF;
END getEmployeeById;
Call From Java:-
Click here

A CallableStatement was executed with nothing returned

I have a Java exception when calling a function that returns nothing:
org.postgresql.util.PSQLException: A CallableStatement was executed with nothing returned.
The Java code is similar to this:
// Procedure call.
CallableStatement proc = con.prepareCall("{ ? = call doquery ( ? ) }");
proc.registerOutParameter(1, Types.Other);
proc.setInt(2, 33434);
proc.execute();
ResultSet results = (ResultSet) proc.getObject(1);
while (results.next()) {
// do something with the results...
}
results.close();
proc.close();
The query is very simple:
select * from table where idTable = 33434;
The query does not return any value because what I'm looking for in postgresql DB does not exist. A sql query is like that, not always we get something in return.
How do you deal with this situations?
PS.- The Postgresql function:
CREATE OR REPLACE FUNCTION doquery(_idTable bigint)
RETURNS TABLE(idTable bigint, name varchar) AS
$BODY$
DECLARE
searchsql text := '';
BEGIN
searchsql := 'SELECT * FROM table
WHERE idTable = ' || _idTable;
RETURN QUERY EXECUTE searchsql;
END
$BODY$
LANGUAGE plpgsql;
Don't use a CallableStatement. They are intended for stored procedures not functions.
As your function returns a resultset, you need to use a select statement:
PreparedStatement pstmt = con.prepareStatement("select * from doquery(?)");
pstmt.setInt(1, 33434);
ResultSet results = pstmt.executeQuery();
while (results.next()) {
// do something with the results...
}
results.close();
proc.close();
Note that the use of dynamic SQL or even PL/pgSQL is not needed. You should also not append parameters to queries (the same way you shouldn't do it in Java as well). Use parameter placeholders:
CREATE OR REPLACE FUNCTION doquery(_idTable bigint)
RETURNS TABLE(idTable bigint, name varchar) AS
$BODY$
BEGIN
RETURN QUERY
SELECT *
FROM table
WHERE idTable = _idTable;
END
$BODY$
LANGUAGE plpgsql;
Or even simpler as a pure SQL function:
CREATE OR REPLACE FUNCTION doquery(_idTable bigint)
RETURNS TABLE(idTable bigint, name varchar) AS
$BODY$
SELECT idtable, name
FROM table
WHERE idTable = _idTable;
$BODY$
LANGUAGE sql;
If you do need dynamic SQL then use placeholders inside the string and pass the parameters to the execute function. Do not concatenate values:
CREATE OR REPLACE FUNCTION doquery(_idTable bigint)
RETURNS TABLE(idTable bigint, name varchar) AS
$BODY$
BEGIN
RETURN QUERY EXECUTE '
SELECT *
FROM table
WHERE idTable = $1'
USING _idTable;
END
$BODY$
LANGUAGE plpgsql;

I can't read in java returned array from plpgsql function

Postgres plpgsql function :
CREATE OR REPLACE FUNCTION usersList()
RETURNS TABLE(at varchar,name varchar,surname varchar) AS $$
BEGIN
RETURN QUERY SELECT * FROM users;
END;
$$ LANGUAGE plpgsql;
And java code
result = Pstatement.executeQuery("Select usersList() ");
while(result.next()) {
System.out.println(result.getString(("at")));
System.out.println(result.getString(("name")));
System.out.println(result.getString(("surname")));
}
Java error sql exception message :
Message: The column name at was not found in this ResultSet.
SQLState: 42703
ErrorCode: 0
How can i return all table columns from a function and then print them in java ?
Postgres plpgsql function :
CREATE OR REPLACE FUNCTION usersList()
RETURNS TABLE(at varchar,name varchar,surname varchar) AS $$
BEGIN
RETURN QUERY SELECT * FROM users;
END;
$$ LANGUAGE plpgsql;
And java code
result = Pstatement.executeQuery("SELECT * FROM usersList() ");
while(result.next()) {
System.out.println(result.getString(("at")));
System.out.println(result.getString(("name")));
System.out.println(result.getString(("surname")));
}
Credits to RealSkeptic && Nick Barnes !!!
You can use result.getMetaData().getColumnCount() to see how many columns you retrieved and then you can call result.getMetaData().getColumnName(x) to check the name of the column (replace x with the number of column).
So technically you should be able to write your code block like so:
result = Pstatement.executeQuery("Select usersList() ");
String mesites[];
while(result.next()) {
int columnCount = result.getMetaData().getColumnCount();
System.out.println("Found:"+columnCount+" columns.");
for(int i=1; i<=columnCount; i++){
System.out.println(result.getString(result.getMetaData().getColumnName(i)));
}
}
Which should then print out any columns retrieved in that result set regardless of names (if any).

How to call function using EclipseLink

How to call an Oracle function which returns sys_refcursor using EclipseLink?
There is a documentation which states about calling a function, but not sure how to call a function which returns sys_refcursor.
http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_namedstoredfunctionquery.htm
I have tried as follows
#NamedStoredFunctionQuery(name = "findEmployees",
functionName = "getEmps",
parameters =
{ #StoredProcedureParameter(queryParameter = "user",
name = "username",
direction = Direction.IN,
type = String.class)
} ,
returnParameter = #StoredProcedureParameter(queryParameter = "c_cursor")
)
Oracle Function
CREATE or REPLACE FUNCTION getEmps (username varchar2)
RETURN SYS_REFCURSOR
AS
c_cursor SYS_REFCURSOR;
BEGIN
OPEN c_cursor FOR
SELECT * FROM employees where emp_no=username;
RETURN c_cursor;
However when I execute, I am getting the following errors
Internal Exception: 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
Error Code: 6550
Call: BEGIN ? := getEmps(username=>?); END;
bind => [=> c_cursor, S7845]
Query: DataReadQuery(name="findEmps" )
at org.eclipse.persistence.internal.jpa.QueryImpl.getDetailedException(QueryImpl.java:378)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:260)
at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:469)
How can I resolve this issue?
I think you must specify the Direction of the functions parmeter
CREATE or REPLACE FUNCTION getEmps (username IN varchar2)
RETURN SYS_REFCURSOR
AS
c_cursor SYS_REFCURSOR;
BEGIN
OPEN c_cursor FOR
SELECT * FROM employees where emp_no=username;
RETURN c_cursor;
Try it, please !
Save the function on database and then execute it with FUNCTION call.
For example, i have an Oracle function called 'SUMACAMPO' that sums two columns of the DB:
And my query:
select Function('SUMACAMPO') from Table t
Java Code:
Query q = em.createQuery("select Function('SUMACAMPO') from Table t");
List<Object[]> resultado= q.getResultList();
LOG.info("Resultado consulta: {}",resultado);
so, the output of execute the query in LOG is:
Resultado consulta: [4413700]

Retrieving a value from Stored Procedure using Native SQL Hibernate

Below is the stored procedure:
create or replace procedure
proc_emp_name(v_emp out emp.emp_name%TYPE, v_empid in emp.emp_id%TYPE)
is
begin
select emp_name into v_emp from emp where emp_id = v_empid;
dbms_output.put_line('Emp Name: ' || v_emp);
dbms_output.put_line('Procedure created successfully!!!');
end;
I want to invoke this using Native SQL, followed this link but not sure how to retrieve the OUT parameter from the Procedure.
http://www.mkyong.com/hibernate/how-to-call-store-procedure-in-hibernate/
Kindly let me know the simplest way to invoke the procedure and get the results out of it.
EDIT
As suggested, checking the docs, I modified the Proc having first parameter as a SYS_REFCURSOR as follows:
create or replace procedure
proc_empname_refcursor(v_empname OUT SYS_REFCURSOR, v_deptid in emp.emp_id%type)
is
begin
open v_empname for select * from dept where dept_id = v_deptid;
end;
I am able to invoke it using NamedQuery but I don't want to add anything in the mapping files because of some other restrictions. I tried the below code for invoking the proc without using NamedQuery but it did not worked out:
Query query = session.createSQLQuery(
"CALL proc_empname_refcursor(?, :deptId)")
.addEntity(Dept.class)
.setParameter("deptId", new Integer(2));
List<Dept> departments = query.list();
for(int i=0; i<departments.size(); i++){
Dept department = (Dept)departments.get(i);
System.out.println("Dept Id: " + department.getDeptId());
System.out.println("Dept Name: " + department.getDeptName());
}
I am getting the exception:
org.hibernate.QueryException: Expected positional parameter count: 1, actual parameters: [] [CALL proc_empname_refcursor(?, :deptId)]
at org.hibernate.impl.AbstractQueryImpl.verifyParameters(AbstractQueryImpl.java:319)
at org.hibernate.impl.SQLQueryImpl.verifyParameters(SQLQueryImpl.java:201)
at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:145)
at com.jdbc.HibernateStartup.main(HibernateStartup.java:70)
Kindly let me know how to resolve this.
I've managed to get an out parameter from a stored procedure using the following code in Hibernate and MS SQL Server:
#Override
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
Connection connection = session.connection();
CallableStatement callable = null;
try {
callable = connection.prepareCall("execute [procedure] ?");
callable.registerOutParameter(1, Types.INTEGER);
callable.execute();
int id = callable.getInt(1);
return id;
} catch (SQLException e) {
(...)
} finally {
(...)
}
}
From Hibernate Docs:
You cannot use stored procedures with Hibernate unless you follow some procedure/function rules.
For Oracle, A function must return a result set. The first parameter of a procedure must be an OUT that returns a result set.

Categories

Resources