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]
Related
when i run below query in my springboot project
select * from activity.activity where data->'userinfo' #> '[{"name": :username}]'::jsonb
i get this error "Could not locate named parameter [username], expecting one of []".
The table has a data column with value as {"userinfo": [{"name": "john"},{"lastname":"cena"}]}
What could be the issue?
PS: i am executing the query using the entity manager to create a native query, and then calling query.getResultList().
CODE:
StringBuffer q = new StringBuffer("select * from activity.activity where data->'userinfo' #> '[{\"name\":").append(" :username").append("}]'::jsonb");
Query query = null;
query = em.createNativeQuery(q.toString(), Activity.class);
query.setParameter("username", getActivityDataRequest.getUserName());
return query.getResultList();
That is a string literal. It cannot contain a parameter. You do have a :jsonb parameter, though. You should use ANSI SQL casting to avoid that.
Instead you should change your query to
String sql = "select * from activity.activity where data->'userinfo' #> CAST(:uname as jsonb)"
// next line is psudocode
String value = JsonBuilder.newArray( JsonBuilder.newObject("name", username) ).toString();
// real code
return em.createNativeQuery(sql, ResultClass.class)
.setParameter("uname", value)
.getResultList();
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;
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) }"
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).
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.