Encountered the symbol \"CLOSE\" after prepareCall - java

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

Related

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.

Setting the out parameter in callable statement

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

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
}

Access an array returned from an oracle procedure

My oracle procedure returns an array of string and I call the procedure from my java method.
When I execute the query I get the following exception.
java.sql.SQLException: ORA-03115: unsupported network datatype or representation
Note:
I have used OracleTypes.ARRAY here but I also tried using Types.ARRAY and it still gave me the same error.
My Java method:
public void searchRecords() throws FinderException{
Session session = getCurrentSession();
Connection con = session.connection();
CallableStatement stmt = null;
String procCall = "call pkg_inquiry.test2(?,?)";
try{
stmt = con.prepareCall(procCall);
stmt.setInt(1, 1);
stmt.registerOutParameter(2, OracleTypes.ARRAY);
//stmt.registerOutParameter(2, Types.ARRAY);
stmt.execute(); //-----------This statement causes exception
}catch(SQLException e){
System.out.println(e.getMessage());
}
}
MY Procedure:
PROCEDURE test2(
p_in in INTEGER,
p_out OUT header_row_vt
)
is
BEGIN
p_out := header_row_vt('NAME', 'AGE', 'CITY', 'STREET');
END test2;
If you want to know I am using Oracle 11.2 and jdbc 11.2
I experienced a similar problem. My first guess was that the driver's sub-version (11.2.0.3) did not match the database's version (11.2.0.2), but this was not the case.
I got it to work eventually by declaring a return type in the database and calling stmt.registerOutParameter(2, OracleTypes.ARRAY, "TYPE_NAME"); instead.
An example for this is provided here:
CallableStatement + registerOutParameter + multiple row result
I cant test your code right now but seems like the issue is following:
If you are using OracleTypes then you should use OracleCallableStatement
OracleCallableStatement cs = con.prepareCall(procCall);
Also if you want to use CallableStatement try java.sql.Types.ARRAY
Cheers !!

"Parameter type conflict" when calling Java Stored Procedure within another Java Stored Procedure

Here's the problem (sorry for the bad english):
i'm working with JDeveloper and Oracle10g, and i have a Java Stored Procedure that is calling another JSP like the code:
int sd = 0;
try {
CallableStatement clstAddRel = conn.prepareCall(" {call FC_RJS_INCLUIR_RELACAO_PRODCAT(?,?)} ");
clstAddRel.registerOutParameter(1, Types.INTEGER);
clstAddRel.setString(1, Integer.toString(id_produto_interno));
clstAddRel.setString(2, ac[i].toString());
clstAddRel.execute();
sd = clstAddRel.getInt(1);
} catch(SQLException e) {
String sqlTeste3 = "insert into ateste values (SQ_ATESTE.nextval, ?)";
PreparedStatement pstTeste3 = conn.prepareStatement(sqlTeste3);
pstTeste3.setString(1,"erro: "+e.getMessage()+ ac[i]);
pstTeste3.execute();
pstTeste3.close();
}
I'm recording the error in a table called ATESTE because this JavaSP is a procedure and not a function, I've to manipulate DML inside.
So, the error message I'm getting is: 'parameter type conflict'...
the function "FC_RJS_INCLUIR_RELACAO_PRODCAT" it's a Java Stored Procedure too, it's already exported to Oracle, and returns an int variable, and i have to read this to decide which webservice i will call from this JavaSP.
I have already tried the OracleTyep.NUMBER in the registerOutParameter.
Anyone knows what i'm doing wrong?
It looks like you are missing a parameter in your call. You register an Integer output parameter, and then you set 2 string parameters. I'm presuming your procedure FC_RJS_INCLUIR_RELACAO_PRODCAT returns an integer value. If so your code should look more like this:
CallableStatement clstAddRel = conn.prepareCall(" { ? = call FC_RJS_INCLUIR_RELACAO_PRODCAT(?,?)} ");
clstAddRel.registerOutParameter(1, Types.INTEGER);
clstAddRel.setString(2, Integer.toString(id_produto_interno));
clstAddRel.setString(3, ac[i].toString());
clstAddRel.execute();

Categories

Resources