Setting the out parameter in callable statement - java

I'm trying to run a stored procedure that returns a resultSet using oracle jdbc.
The procedure is as follows.
create or replace procedure display_players (rset OUT sys_refcursor)
as
Begin
open rset for select * from player_data;
End;
/
The java code is as follows
try {
sql = "{call display_players()}";
call = conn.prepareCall(sql);
call.execute();
rs = call.getResultSet();
while(rs.next()){
System.out.println(rs.getString("name") + " : " + rs.getString("club"));
}
I tried to register the out parameter as
call = conn.prepareCall("{call display_players(?)}");
call.registerOutParameter(1, OracleTypes.CURSOR);
But that dint work nor is the current code working as i get a null pointer exception which means the result set is not being returned.
how do i achieve this?

I think you haven't quite worked out how to get the result set from an OUT parameter from a stored procedure call.
Firstly, you need to register the OUT parameter, as in your second code sample:
call = conn.prepareCall("{call display_players(?)}");
call.registerOutParameter(1, OracleTypes.CURSOR);
However, once you've executed the statement, it's not correct to call.getResultSet() to get at the result set in the OUT parameter. For example, suppose you were calling a stored procedure that had two OUT parameters returning cursors. Which one should call.getResultSet() return?
The trick is to use call.getObject(...) to get the value of the parameter from call as an Object and then cast this to a ResultSet. In other words, replace the line
rs = call.getResultSet();
with
rs = (ResultSet)call.getObject(1);

Related

Encountered the symbol \"CLOSE\" after prepareCall

pl/sql code TRIGER1
Here is my pl/sql code that I am trying to execute by prepareCall
String sql = String.format(FunctionCalls.TRIGGER1);
CallableStatement callableStatement = null;
Integer result = null;
String err = null;
try {
callableStatement = connection.prepareCall(sql);
callableStatement.execute();
result = callableStatement.getInt("RES_CODE");
err = callableStatement.getString("RES_DESC" );
After executing, I want to get two of the declared parameters, RES_CODE and RES_DESC, but I get this error instead:
java.sql.SQLException: ORA-06550: line 2, column 1274:\nPLS-00103: Encountered the symbol \"CLOSE\" \n
After googling, many people think that the problem is in cursor that you need to declare cursors in declaration section and the process cursor after BEGIN, but I am doing аs it says. In PL/SQL Developer it works fine you can see in image.
Is it possible in java get declared parameter after execute ?
Is it possible execute TRIGER1 pl/sql code and get the two parameters RES_CODE and RES_DESC?
As javadoc of CallableStatement says: "The interface used to execute SQL stored procedures."
The javadoc even shows the syntax you must use, which starts with a { brace.
Your SQL is not a stored procedure, it is a PL/SQL block.
Also, RES_CODE and RES_DESC are not parameters.
What you're trying to do is entirely wrong, and if some site has shown you to do it this way, please stop using that site immediately.
Try actually creating a stored procedure with the code in question, and define actual parameters to that store procedure.
Syntax for that is:
CREATE PROCEDURE xxx ( RES_CODE OUT number, RES_DESC OUT varchar2 ) AS
variable declarations here
BEGIN
code here
END;
/
Then you call that procedure using:
String sql = "{call xxx(?,?)}";
try (CallableStatement stmt = conn.prepareCall(sql)) {
stmt.registerOutParameter(1, TYPES.INTEGER);
stmt.registerOutParameter(2, TYPES.VARCHAR);
stmt.execute();
result = stmt.getInt(1);
err = stmt.getString(2);
}

java get stored procedure response

how do i get the Store procedure response in java ?
when i run this in SQL i get a response
DECLARE
result NUMBER;
begin
result := apps.xx01_cpc_ap_pkg.xx01_create_invoice_f(8309, 4795, 146.00);
dbms_output.put_line(result);
end;
this is my java code
i tried many option - but i keep failing on how to fetch the response
in this part resultSet.getInt(4))
CallableStatement stmt = null;
String spCallRequest = "{? = call apps.xx01_cpc_ap_pkg.xx01_create_invoice_f(?, ?, ? )}";
stmt = oraAppUtils.connection.prepareCall(spCallRequest);
stmt.setString(1,paymentRequest.healthFacilityCode);
stmt.setString(2,paymentRequest.batchId);
stmt.setDouble(3,Double.parseDouble(paymentRequest.tariffAmount));
stmt.registerOutParameter(4, java.sql.Types.INTEGER);
resultSet = stmt.executeQuery();
System.out.println ("invoice id ="+resultSet.getInt(4));
ok - just for documentation in case some else needs it... this is the SP it has a function
CREATE OR REPLACE PACKAGE APPS.XX01_CPC_AP_PKG
AS
PROCEDURE XX01_CREATE_INVOICE (P_HF_CODE IN VARCHAR2,
P_BATCH_ID IN VARCHAR2,
P_AMOUNT IN NUMBER,
x_invoice_id OUT NUMBER/*,
x_error_code OUT VARCHAR2,
x_error_msg OUT VARCHAR2,
x_err_comments OUT VARCHAR2,
x_code OUT NUMBER,
x_source OUT VARCHAR2*/);
FUNCTION XX01_CREATE_INVOICE_F (P_HF_CODE IN VARCHAR2,
P_BATCH_ID IN VARCHAR2,
P_AMOUNT IN NUMBER) RETURN NUMBER;
so originaly i called the function - it didn't work - i change the code to the following code and it works
String spCallRequest = "BEGIN apps.xx01_cpc_ap_pkg.xx01_create_invoice(?, ?, ?,? ); END ; ";
stmt = oraAppUtils.connection.prepareCall(spCallRequest);
stmt.setString(1,paymentRequest.healthFacilityCode);
stmt.setString(2,paymentRequest.batchId);
stmt.setDouble(3,Double.parseDouble(paymentRequest.tariffAmount));
stmt.registerOutParameter(4, java.sql.Types.INTEGER);
stmt.execute();
System.out.println ("invoice id ="+stmt.getInt(4));
TL;DR
You did not call ResultSet#next()
Reason
From linked docs:
A ResultSet cursor is initially positioned before the first row; the
first call to the method next makes the first row the current row; the
second call makes the second row the current row, and so on.
Fix
Your code should look like this:
stmt.registerOutParameter(4, java.sql.Types.INTEGER);
resultSet = stmt.executeQuery();
if(resultSet.next()) {
System.out.println ("invoice id ="+resultSet.getInt(4));
} else {
//this should not happen
}
Your question didn't explicitly mention JDBC as the API that you must use, so perhaps, you're open to third party utilities that work on top of JDBC? For example, jOOQ's code generator can be used to generate stubs for all of your stored procedures. In your case, you could simply call the stub like this:
int result = Xx01CpcApPkg.xx01CreateInvoiceF(
configuration, // This object contains your JDBC Connection
paymentRequest.healthFacilityCode,
paymentRequest.batchId,
Double.parseDouble(paymentRequest.tariffAmount)
);
These objects are generated by jOOQ:
Xx01CpcApPkg: A class representing your PL/SQL package
xx01CreateInvoiceF(): A method representing your stored function
Behind the scenes, this does exactly what the accepted answer does, but:
You don't have to work with strings
You don't have to remember data types and parameter order
When you change the procedure in your database, and regenerate the code, then your client code stops compiling, so you'll notice the problem early on
Disclaimer: I work for the company behind jOOQ.

Sql query with bind variables execution in Jdbc

I have a sql query like this.
select "DEPT"."DEPTNO" as "DEPTNO1",
"DEPT"."DNAME" as "DNAME1",
"DEPT"."LOC" as "LOC1",
"EMP"."COMM" as "COMM1",
"EMP"."EMPNO" as "EMPNO1",
"EMP"."ENAME" as "ENAME1",
"EMP"."HIREDATE" as "HIREDATE1",
"EMP"."JOB" as "JOB1",
"EMP"."MGR" as "MGR1",
"EMP"."SAL" as "SAL1"
from "EMP" , "DEPT" where "DEPT"."DEPTNO" in (:DeptNo)
//This is the Jdbc code
Class.forName(DB_DRIVER);
dbConnection = DriverManager.getConnection(DB_CONNECTION, DB_USER, DB_PASSWORD);
Statement statment = dbConnection.createStatement();
result = statment.execute(query);//query is above sql query
When i run above query in Oracle sql developer works perfectly.But when i run it with above jdbc code it is throwing Not all variables bound exception.
How to run above query in JDBC
replace :deptno in your query with a ?.
and instead of instantiating statement use the following:
PreparedStatement stmt=con.prepareStatement(query);
stmt.setInt(1,deptno); //1 is for the first question mark
where deptno holds the value for which you want to execute the query.
Through PrepredStatement interface we can use parametrized query which is compiled only once and has performance advantage in comparison to the Statement interface.
You created a Query with bind variable and you never set it.
Use OraclePreparedStatement and its method setStringAtName()
statement.setStringAtName("DeptNo","<<your Value>>");
If not OraclePreparedStatement, you can just put it as ?1 in your Query string
and use,
statement.setString(1,"<<your Value>>");
If in case, you don't know how many bind variables you get, you have capture the bind variables in a map and prepare a list and set it accordingly!
Else your requirement is unachievable!
Get the query dynamically from the report.
From this query we need to split querystring to get number of bind variables and placing those bind variables in a HashMap.HashMap is like
{DeptName =1, Job =1, DeptNo =1}
From this hashmap,need to replace the query bind variable with ?.For this we need to do like
bindkey = entry1.getKey().toString();
String bindkeyreplace =":".concat(bindkey).trim();
String bindkeyreplacestring = "?";
query = query.replace(bindkeyreplace, bindkeyreplacestring);
Then we will get dynamic query coming from the report with ? instead of :bindvariable
PreparedStatement prestmt = dbConnection.prepareStatement(query);
for (int i = 0; i < bindParamMap.size(); i++) {
prestmt.setInt(i + 1, 0);//Setting default value to check the query is running successfully or not
}
result = prestmt.execute();
If in case, we don't know how many bind variables we get then this approach is running successfully for me.
Use this syntax,EMP.DNAME as DNAME1. I mean your dot and as must be inside the double quotes.
The variable DeptNo must be bound to a value before you execute the statement like below.
DriverManager.getConnection(DB_CONNECTION, DB_USER, DB_PASSWORD);
Statement statment = dbConnection.createStatement();
//Bind deptno to a value
statment.setParameter("DeptNo",5);
result = statment.execute(query);
You must set values for all the variables in your prepared statement othwerise you cannot execute the statement. If you receive the query to execute itself as an input then you should also get the parameters and its values also as input. Something like below
public <returnType> executeQuery(String queryStr, Map<String,Object> params) {
//Code to create connecitno and statment from queryStr.
//Bind deptno to a value
for(int i=0;i<params.size(),i++) {
//Get entry set from map
statment.setParameter(entryset.getKey(),entryset.getValue());
}
result = statment.execute(query);
//return or work on the result
}

CallableStatement PostgreSQL :Invalid number of parameters error

Im trying to write sample stored functions in postgresql and call them using the CallableStatement offered by JDBC.
Here's some my test code
Consumer bean =new Consumer();
CallableStatement pstmt = null;
try {
con.setAutoCommit(false);
String query = "{ ? = call getData( ? ) }";
pstmt = con.prepareCall(query);
pstmt.registerOutParameter(1, Types.OTHER);
pstmt.setInt(2,5);
pstmt.execute(); // execute update statement
bean=(Consumer)pstmt.getObject(1);
System.out.println("bean"+bean.getConsumer_name());
And my Stored function is of the form .
CREATE FUNCTION getData(int) RETURNS SETOF db_consumer AS $$
SELECT * FROM db_consumer WHERE consumer_id = $1;
$$ LANGUAGE SQL;
However, I'm getting the following error when I try to run the code .
org.postgresql.util.PSQLException: A CallableStatement was executed with an invalid number of parameters .
Any idea why this could be happening?
I don't think you need a CallableStatement as you should be able to run select * from getData(5) directly:
PreparedStatement pstmt = con.prepareStatement("select * from getData(?)")
pstmt.setInt(1,5);
ResultSet rs = pstmt.execute();
while (rs.next()) {
System.out.println(rs.getString(1));
}
You are trying to call a SETOFF function via a Callable Statement. That's not going to happen! You'll always get an error.
PostgreSQL's stored functions can return results in two different ways. The function may return either a refcursor value or a SETOF some datatype. Depending on which of these return methods are used determines how the function should be called.
Functions that return data as a set should not be called via the CallableStatement interface, but instead should use the normal Statement or PreparedStatement interfaces.

Java named parameter's name (for Oracle JDBC function result)

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);

Categories

Resources