I have a function which uses sys_Refcursor
create or replace function get_employee
(p_loc in number)
return sys_refcursor
as
l_rc sys_refcursor;
begin
open l_rc
for select a.first_name, a.last_name, b.department_name
from employees a,
departments b
where a.department_id=b.department_id
and location_id=p_loc;
return l_rc;
end;
and running this in SQL developer
select (get_employee(5)) from dual;
In Java I used
strSql+="select (get_employee(5)) from dual";
resultSet = selectStatement.executeQuery(strSql);
while (resultSet.next()) {
System.out.println("here is the " + resultSet.getString(1) );
System.out.println("here is the " + resultSet.getString(2) );
}
But the above code is returning the resultset as Null.
Could you please tell me the ways we can retrieve the result values of that function in Java?
Thanks in Advance
You do not need to execuse query to get ref cusros.
create or replace function get_refcursor
return sys_refcursor
is
c sys_refcursor;
begin
open c for select 1 x from dual;
return c;
end;
DriverManager.registerDriver ( new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:#****:1521:***","***","***");
OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall("{ ? = call get_refcursor }"); ;
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.execute();
ResultSet rs = (ResultSet)cstmt.getObject(1);
while(rs.next()) {
System.out.println('Result: '+rs.getBigDecimal(1));
}
rs.close();
cstmt.close();
Result: 1
Related
I have a stored procedure in SQL which can run in SQL without problems. But when I use Java to call it, the code can run but stored procedure cannot be called. Here's my code:
public int countPV(int value){
Connection conn = null;
ResultSet rs = null;
try {
conn = MyConection.getConnection();
CallableStatement cstmt = conn.prepareCall("{call countPV(?)}");
cstmt.setInt(1, value);
} catch (Exception e) {
e.printStackTrace();
return 0;
}finally{
try {
MyConection.closeConnection(conn, null, rs);
} catch (Exception e) {
}
}
return 1;
}
And here is my stored procedure in SQL:
CREATE procedure countPV (#pID int)
as
begin
WHILE (2>1)
BEGIN
update tblUser
set countx = countx + 1
where ID = #pID
SET #pID = (select parentID from tblUser where ID = #pID)
if(#pID = (select parentID from tblUser where ID = #pID))
break;
END
end
You need to call CallableStatement#execute() in your method.
CallableStatement cstmt = conn.prepareCall("{call countPV(?)}");
cstmt.setInt(1, value);
cstmt.execute(); // MISSING!
https://docs.oracle.com/javase/7/docs/api/java/sql/CallableStatement.html
Since CallableStatemnt is extending PreparedStatement,it inherited it's executing methods (execute, executeQuery, executeUpdate) to be executed like normal quires.
I Would like to recommend using setQueryTimeout for any stored procedure calls to avoid timeout issues.
So I've got a function that checks how many cancellations are in my booking table:
CREATE OR REPLACE FUNCTION total_cancellations
RETURN number IS
t_canc number := 0;
BEGIN
SELECT count(*) into t_canc
FROM booking where status = 'CANCELLED';
RETURN t_canc;
END;
/
To execute his in sql I use:
set serveroutput on
DECLARE
c number;
BEGIN
c := total_cancellations();
dbms_output.put_line('Total no. of Cancellations: ' || c);
END;
/
My result is:
anonymous block completed
Total no. of Cancellations: 1
My question is can someone help me call the function in JAVA, I have tried but with no luck.
Java provides CallableStatements for such purposes .
CallableStatement cstmt = conn.prepareCall("{? = CALL total_cancellations()}");
cstmt.registerOutParameter(1, Types.INTEGER);
cstmt.setInt(2, acctNo);
cstmt.executeUpdate();
int cancel= cstmt.getInt(1);
System.out.print("Cancellation is "+cancel);
will print the same as you do in the pl/sql. As per docs Connection#prepareCall(),
Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.
You can also pass parameters for the function . for ex ,
conn.prepareCall("{? = CALL total_cancellations(?)}");
cstmt.setInt(2, value);
will pass the values to the function as input parameter.
Hope this helps !
Prepare a Callable Statement
There are two formats available, the
familiar block syntax used by Oracle and the ANSI 92 standard syntax.
In the case of our sample program, the block syntax has the form:
CallableStatement vStatement =
vDatabaseConnection.prepareCall( "begin ? := javatest( ?, ? ); end;" );
The ANSI 92 syntax has the form:
CallableStatement vStatement =
vDatabaseConnection.prepareCall( "{ ? = call javatest( ?, ? )}");
source
If you receive the below error, you might want to use the first format.
total_cancellations is not a procedure or is undefined error.
Sample code.
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:#xx.xxx.xx.xxx:1521:xxx", "user","pass");
CallableStatement cstmt = conn.prepareCall("begin ? := TEST_FUNC(?,?); end;");
cstmt.registerOutParameter(1, Types.INTEGER);
cstmt.setString(2, "Test");
cstmt.setInt(3, 1001);
cstmt.execute();
int result = cstmt.getInt(1);
System.out.print("Result: " + result);
cstmt.close();
conn.close();
How to call oracle function from java?.
I have a oracle function aaa.fucntion(number,date);, this method returns true or false. how do call this from java and get the returned value?
I am using Hibernate
this is what i tried,
Session session = null;
String associateHistorySQL="";
try {
session = HibernateUtil.currentSession();
associateHistorySQL = "SELECT aa.myFunction(:aorId,:givenDate) from dual";
Query associateHistoryQuery = session.createQuery(associateHistorySQL);
associateHistoryQuery.setParameter("aorId", associateOfficeRecordId);
associateHistoryQuery.setParameter("givenDate", date);
List associateHistoryList = associateHistoryQuery.list();
if (associateHistoryList != null && associateHistoryList.size() > 0 && new Integer(associateHistoryQuery.uniqueResult().toString()) > 0)
return true;
else
return false;
} finally {
HibernateUtil.cleanUpHibernateFromDao(false);
}
This is the exception i get unexpected token: aa: line 1:1: unexpected token: aa
thanks
There are actually multiple ways of doing so. But the easiest of them all is firing a query.
Here's how to do it.
String sql="select myFunction('"+number+"','"+date"') from dual";
statement.execute(sql);
Set the input and output parameters if you are using JDBC.
If you are using hibernate use Named Queries something like this:
YourMapping.hbm.xml
<sql-query name="my_function" callable="true">
<return alias="demo" class="net.bean.Demo">
<return-property name="id" column="id"/>
<return-property name="fname" column="fname"/>
<return-property name="lname" column="lname"/>
</return>
{?=call demoFunc(:param1,:param2)}
</sql-query>
Now this will create a Named Query for the function
Next thing to do is simply call it using following code
Query query=session.getNamedQuery("my_function");
query.setParameter("parma1",date);
query.setParameter("parma2",number);
query.executeUpdate();
Note that in hbm.xml file the return class name and properties exists only apply if you have mapped the returning values if the function returning appropriate values.
Use session.doWork from hibernate.
How to call a Oracle function from hibernate with return parameter?
From Oracle documentation -
http://docs.oracle.com/cd/F49540_01/DOC/java.815/a64686/04_call5.htm
FUNCTION balance (acct_id NUMBER) RETURN NUMBER IS
acct_bal NUMBER;
BEGIN
SELECT bal INTO acct_bal FROM accts
WHERE acct_no = acct_id;
RETURN acct_bal;
END;
From a JDBC program, your call to the function balance might look like this:
CallableStatement cstmt = conn.prepareCall("{? = CALL balance(?)}");
cstmt.registerOutParameter(1, Types.FLOAT);
cstmt.setInt(2, acctNo);
cstmt.executeUpdate();
float acctBal = cstmt.getFloat(1);
oracle function:
FUNCTION ap_ch_get_acct_balances (VAR_PI_MOB_NO_ACCT_NO VARCHAR2,
VAR_REPLY_CODE OUT NUMBER, VAR_EXT_RESPONSE OUT VARCHAR2, VAR_PO_ACC_BAL OUT CHAR,
VAR_PO_ACCT_NO OUT CHAR)
call in java:
String call = "{ ? = call FCRLIVE.AP_CH_GET_ACCT_BALANCES(?, ?, ?, ?, ?) }";
You can use CallableStatement
String sql="begin ? := aaaa.fucntion(?,?); end;";
CallableStatement stmt = connection.prepareCall(sql);
stmt.registerOutParameter(1, OracleTypes.BOOLEAN);
stmt.setInt(2, number);
stmt.setTimestamp(3, date);
stmt.execute();
After that you can read the returned value with:
stmt.getBoolean(1)
// Oracle Function
create or replace function addtwono(a in number, b in number) return varchar2 is
Result varchar2(10);
begin
result:= a + b;
--c:= result;
return('SUCCESS');
end ;
// Java Code ==========================================
String query = "begin ? := user.addtwono(?,?); end;";
CallableStatement st = connection.prepareCall(query);
st.registerOutParameter(1, OracleTypes.VARCHAR);
st.setInt(2, 10);
st.setInt(3, 15);
st.execute();
String rtn = st.getString(1);
I have a stored procedure
CREATE OR REPLACE FUNCTION fun_retrieve_vector_receipt_payment_details(character varying, integer, character varying, character varying, character varying, refcursor) RETURNS refcursor AS
this is my java code
con.setAutoCommit(false);
String sql = "{call fun_retrieve_vector_receipt_payment_details(?,?,?,?,?,?)}";
callableStatement = con.prepareCall(sql);
callableStatement.setString(1, "PAYMENT");
callableStatement.setInt(2, 41);
callableStatement.setString(3, "2011-05-06");
callableStatement.setString(4, "2013-05-06");
callableStatement.setString(5, "Y");
callableStatement.setObject(6, rs);
callableStatement.registerOutParameter(6, Types.OTHER);
callableStatement.execute();
ResultSet resultSet = (ResultSet) callableStatement.getObject(6);
// rs = callableStatement.executeQuery();
boolean next = resultSet.next();
if (next)
{
System.out.println(resultSet.getString(1));
}
why do i get resultset as null?
what should i pass as refcursor as parameter from java?
i am using postgres as my database
Try this approach:
Statement stmt = conn.createStatement();
stmt.execute("CREATE OR REPLACE FUNCTION "
+" fun_retrieve_vector_receipt_payment_details(x1 integer, x2 integer )"
+ " RETURNS refcursor AS '"
+ " DECLARE "
+ " mycur refcursor; "
+ " BEGIN "
+ " OPEN mycur FOR SELECT x FROM generate_series( x1, x2 ) x; "
+ " RETURN mycur; "
+ " END;' language plpgsql");
stmt.close();
conn.setAutoCommit(false);
CallableStatement proc = conn.prepareCall(
"{ ? = call fun_retrieve_vector_receipt_payment_details( ?, ? ) }");
proc.registerOutParameter(1, Types.OTHER);
proc.setInt(2 , 13 );
proc.setInt(3 , 17 );
proc.execute();
ResultSet results = (ResultSet) proc.getObject(1);
while (results.next()) {
System.out.println(results.getString(1));
}
results.close();
proc.close();
conn.close();
Run ...
13
14
15
16
17
refcursor is a name of cursor - so it is string. So you have to get a this name, and you can pass it as string:
postgres=# begin;
BEGIN
Time: 0.398 ms
postgres=# declare xxx cursor for select * from f1;
DECLARE CURSOR
Time: 23.409 ms
postgres=# select fx('xxx');
NOTICE: (10,20)
NOTICE: (340,30)
fx
────
(1 row)
commit;
CREATE OR REPLACE FUNCTION public.fx(refcursor)
RETURNS void
LANGUAGE plpgsql
AS $function$
declare r record;
begin
while true
loop
fetch $1 into r;
exit when not found;
raise notice '%', r;
end loop;
end;
$function$
I must use PostgreSQL but I have a little problem when I try to read a function in Java.
My function:
CREATE OR REPLACE FUNCTION tiena.RecursosData7(x text, OUT id text, OUT valor text)RETURNS SETOF record
AS
'
SELECT recursodc.idrecursodc, recursodc.valorfonte
FROM tiena.recursodc
WHERE valorfonte=$1;
'
LANGUAGE 'sql';
Then in Java I'm trying to read the function this way:
try {
if (AbrirConexao()) {
conn.setAutoCommit(false);
proc = conn.prepareCall("{ call tiena.recursosdata7(?,?, ?)}");
proc.setString(1,"IG - SP");
proc.registerOutParameter(2, Types.VARCHAR);
proc.registerOutParameter(3, Types.VARCHAR);
//proc.execute();
//resSet = (ResultSet) proc.getObject(1);
resSet = proc.executeQuery();
while(resSet.next())
{
String id = resSet.getString(1);
String fonte = resSet.getString(2);
System.out.println("id : "+ id +", fonte: "+ fonte);
}
proc.close();
}
But I always get the same error.
Erro : Nenhum resultado foi retornado pela consulta.
org.postgresql.util.PSQLException: Nenhum resultado foi retornado pela consulta.
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:274)
at LerArquivos.ConexaoBD.RecuperarIDRecurso2(ConexaoBD.java:117)
at upload_cg.Main.main(Main.java:24)
I tried to move the location of the parameters, the function and i search a lot but I don't found the solution. Do you have any suggestions?
Bellninita, consider using a cursor instead. Here are example Java and SQL code that has components similar to what you appear to need. This is similar to the production code used for the same purpose:
protected Fault getFault(Integer dataCode, Integer faultCode,
GregorianCalendar downloadTime, IFilterEncoder filter, FaultType faultType, boolean verbose) {
// verbose: flag to display logging statements.
Fault fault = new Fault(faultCode, 0);
try {
// We must be inside a transaction for cursors to work.
conn.setAutoCommit(false);
// Procedure call: getFault(integer, text, timestamp, integer)
proc = conn.prepareCall("{ ? = call getfaultCount(?, ?, ?, ?, ?) }");
proc.registerOutParameter(1, Types.OTHER);
proc.setInt(2, dataCode);
proc.setInt(3, faultCode);
Timestamp ts = new Timestamp(downloadTime.getTimeInMillis());
cal.setTimeZone(downloadTime.getTimeZone());
proc.setTimestamp(4, ts, cal);
proc.setInt(5, filter.getEncodedFilter());
proc.setString(6, faultType.toString());
proc.execute();
if(verbose) {
log.logInfo(this.getClass().getName(), "SQL: " + proc.toString());
}
results = (ResultSet) proc.getObject(1);
while (results.next()) {
//Do something with the results here
}
} catch (SQLException e) {
//Log or handle exceptions here
}
return fault;
}
Here is the SQL that is inside the function (aka, Stored Procedure):
CREATE OR REPLACE FUNCTION getfaultcount(_dataCodeid integer, _faultcode integer, _downloadtime timestamp without time zone, _filterbitmap integer, _faulttype text)
RETURNS refcursor AS
$BODY$
DECLARE mycurs refcursor;
BEGIN
OPEN mycurs FOR
SELECT count(*) as faultcount, _downloadtime as downloadtime
FROM fs_fault f
JOIN download_time d ON f.downloadtimeid = d.id
WHERE f.faultcode = _faultcode
AND f.statusid IN(2, 4)
AND d.downloadtime = _downloadtime
AND d.dataCodeid = _dataCodeid
GROUP BY f.faultcode
;
RETURN mycurs;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION getfaultcount(integer, integer, timestamp without time zone, integer, text) OWNER TO postgres;
The best way is to use the set returning function in a FROM clause of a SELECT. There is no need to use a CallableStatement, a regular PreparedStatement will work just fine.
PreparedStatement pstmt = conn.prepareStatement("select * from tiena.recursosdata7(?)");
proc.setString(1,"IG - SP");
ResultSet resSet = pstmt.executeQuery();
while(resSet.next())
{
String id = resSet.getString(1);
String fonte = resSet.getString(2);
System.out.println("id : "+ id +", fonte: "+ fonte);
}
pstmt.close();