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);
Related
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();
I have a PL/SQL function as follows which returns an Oracle type (PROCESSEXCLEFILEARGS)
FUNCTION PROCESS_FILE_INTERNAL
(
i_Filename VARCHAR2,
i_EventType NUMBER
)
RETURN PROCESSEXCELFILEARGS
I have to call this function from Java and my Java Method looks as follows
OracleCallableStatement cstmt = null;
try{
OracleDriver ora = new OracleDriver();
DriverManager.registerDriver(ora);
Connection connection = ora.defaultConnection();
String call = "{ ? = call NEUTRINO_META.PKG_EXCEL.PROCESS_FILE_INTERNAL(?, ?) }";
cstmt = (OracleCallableStatement)connection.prepareCall(call);
cstmt.setQueryTimeout(1800);
cstmt.registerOutParameter(1, OracleTypes.OTHER, "NEUTRINO_META.PROCESSEXCELFILEARGS");
cstmt.setString(2, filename);
cstmt.setDouble(3, eventType);
cstmt.execute();
OracleObjects.ProcessExcelFileArgsobj = (OracleObjects.ProcessExcelFileArgs)cstmt.getObject(1);
connection.commit();
}
catch (SQLException e){
WriteEventToDb(e.getMessage());
}
finally{
if (cstmt != null){
cstmt.close();
}
}
OracleObject.ProcessExcelFileArgs is implementing SQLData, and the readSQl(..) and writeSQL(..) method are implemented properly to read and write the types fields.
But when i run this java method I get a SQLException with message 'Invalid column type: 1111'
Can anyone let me know if there is anything wrong in the approach I took, or if there is any other way to retrieve the return oracle type as a java object.
EDIT:
create or replace
TYPE PROCESSEXCELFILEARGS FORCE AS OBJECT
(
FullFilePath VARCHAR2(700),
Filename VARCHAR2(200),
Graph TYPEGRAPHDATA
)
please not that TYPEGRAPHDATA is another user defined Oracle type at schema level
thanks
You case use oracle.sql.STRUCT class. Easiest example:
In Oracle:
create type type_dummy is object (
id int,
name varchar2(10)
)
/
create or replace function get_type_dummy
return type_dummy
is
begin
return type_dummy(1,'ABCDe');
end;
/
In Java:
class TypeDummy {
public Long id;
public String name;
}
try {
DriverManager.registerDriver ( new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:#ods.fors.ru:1521:test","odh","odh");
OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall("{ ? = call get_type_dummy }"); ;
cstmt.registerOutParameter(1, OracleTypes.JAVA_STRUCT, "TYPE_DUMMY");
cstmt.execute();
oracle.sql.STRUCT td = (oracle.sql.STRUCT)cstmt.getObject(1);
Object[] x = td.getAttributes();
TypeDummy ntd = new TypeDummy();
ntd.id = ((BigDecimal)x[0]).longValue();
ntd.name = (String)x[1];
System.out.println(ntd.id);
System.out.println(ntd.name);
cstmt.close();
}
...
Output:
1
ABCDe
ok I managed to get the returned oracle type as a java object by using the following code.
try{
Map rtn = connection.getTypeMap();
rtn.put("NEUTRINO_META.PROCESSEXCELFILEARGS", Class.forName("OracleObjects.ProcessExcelFileArgs"));
String call = "{ ? = call NEUTRINO_META.PKG_EXCEL.PROCESS_FILE_INTERNAL(?, ?) }";
cstmt = (OracleCallableStatement)connection.prepareCall(call);
cstmt.setQueryTimeout(1800);
cstmt.registerOutParameter(1, OracleTypes.STRUCT, "NEUTRINO_META.PROCESSEXCELFILEARGS");
cstmt.setString(2, filename);
cstmt.setDouble(3, eventType);
cstmt.execute();
ProcessExcelFileArgs args = (ProcessExcelFileArgs)cstmt.getObject(1, rtn);
}
catch (SQLException e){
WriteEventToDb(e.getMessage());
}
finally{
if (cstmt != null){
cstmt.close();
}
}
This worked by my ProcessExcelFileArgs class having implemented java.sql.SQLData, and by adding to Oracletype to java class mapping to the connection type map.
You have an Oracle type is RECORD:
TYPE my_type IS RECORD (
foo VARCHAR2 (12)
);
In oracle your function return a PIPELINE:
FUNCTION my_funtion (
foo VARCHAR2,
bar VARCHAR2
)
RETURN my_type PIPELINED
In java, you can use the table funtion, and then Retrieve values from the ResultSet
select * from table (URGP.PKG_AG_SIR_MEW.RECUPERARPERSONAPORNRODOC(?,?))
Here, I can't see any particular need to get back table data from a package function, using a CallableStatement object. Instead, we can use a normal sql query to wrap up the results and fetch them into a normal java resultset. Doing so, we avoid trying to find a painful solution adjusting the package function (which uses package-level types), leaving the function and package types intact, as well as continue benefiting from using the unknowing internal functionality and speed of the pipelined plsql function. Panos Zafiropoulos.
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
In java code:
CallableStatement cs=null;
int bcode=1;
int dcode=3;
int noftab=3;
String sql2 = "{? = call public.insertdepttables('"+bcode+"','"+dcode+"','"+noftab+"')}";
cs = conn.prepareCall(sql2);
cs.registerOutParameter(1,Types.INTEGER);
rset1=cs.getInt(1);
system.out.println("success="+rest1);
In insertdepttables:(Function in my db-postgresql)
CREATE OR REPLACE FUNCTION public.insertdepttables
(
IN branch_code integer,
IN dept_code integer,
IN no_tables integer
)
RETURNS integer AS
$$
DECLARE
count integer;
begin
IF no_tables>0 THEN
LOOP
insert into t_dept_tables(branch_code,dept_code,table_no)values(branch_code,dept_code,no_tables);
no_tables=no_tables-1;
Count=count+1;
EXIT when no_tables =0;
END LOOP ;
END IF;
RETURN count;
end
$$
actually i need to insert the no_table (i.e.,3) times row in my t_dept_tables in postgresql. So wat i have done is i hav written functions in database. I need to call it from java code. So I used callable stmt there:
My output should be like this in db:
bcode dcode table_no
1 3 1
1 3 2
1 3 3
Now while executing java code,
I'm getting the result as,
console:
success=3
but 3 rows arent inserted in db, but while executing the function in my db, the values get inserted. So no wrong in my db function. please help me to sort this out.
Are you sure you haven't forgot to actually call statement, like:
cs.executeQuery();
...
cs.close();
BTW, your task could be achieved without functions, like (don't use string concatenation, use parameter values):
String stm = "insert into t_dept_tables(branch_code,dept_code,table_no) values(branch_code,dept_code,no_tables); VALUES(?, ?, ?)";
cs = con.prepareStatement(stm);
cs.setInt(1, id);
cs.setInt(3, id);
cs.setInt(3, id);
rs = cs.executeUpdate();
I'm going to call a function, and set some parameters by name, example:
Connection c = null;
ResultSet rs = null;
String query;
PreparedStatement ps;
CallableStatement cs = null;
try {
c = DbUtils.getConnection();
cs = c.prepareCall("{? = call get_proc_name(?, ?) }");
cs.registerOutParameter(1, OracleTypes.VARCHAR);
cs.setInt("in_proc_type", ProcTypes.SELECT);
cs.setLong("in_table_id", tableId);
// here I should use something like cs.registerOutParameter("result", OracleTypes.VARCHAR);
cs.execute();
PL/SQL function parameters are:
CREATE OR REPLACE FUNCTION get_proc_name
(
in_proc_type IN NUMBER, /*1 - insert, 2 - update, 3 - delete, 4 - select*/
in_table_name IN VARCHAR2 := NULL,
in_table_id IN NUMBER := NULL,
in_table_type_id IN NUMBER := NULL,
is_new IN NUMBER := 0
) RETURN VARCHAR2
The question is how to register result as an out parameter, and then get it from oracle to java?
I can register in/out parameters by name, because I know theirs names from function, but I don't know how go get function result, what variable name use for it.
Manuals describe only usage in/out params with procedures, not functions.
Oracle version: 11.1.0.6.0
Java version: 1.6.0_14
The solution is to use only indexes for settings parameters. Such code works as expected (mixing indexes and named parameters doesn't work; so, the problem of using named parameter for result variable could not be solved, imho):
c = DbUtils.getConnection();
cs = c.prepareCall("{? = call get_proc_name(in_proc_type => ?, in_table_id => ?) }");
cs.registerOutParameter(1, java.sql.Types.VARCHAR);
cs.setInt(2, ProcTypes.SELECT);
cs.setLong(3, tableId);
cs.execute();
String procName = cs.getString(1);
cs.close();
CallableStatement has a bunch of registerXXX methods that take index.
That's how you register the result. It is parameter number 1.
In your case,
cs.registerOutParameter( 1, java.sql.Types.VARCHAR);
<SPECULATION>
BTW, because you are using index for result, you may need to use index-oriented setXXX methods and provide a full parameter list.
</SPECULATION>
You register the function result as if it were the first parameter. Obviously, this shifts the numbering of the actual parameters.
Your already existing line
cs.registerOutParameter(1, OracleTypes.VARCHAR);
is all it takes. After the call, get your result like this:
String result = cs.getString(1);