I'm connecting to SQL Server (2005) through Java using the Microsoft SQL Server JDBC Driver 2.0.
How do I get the return value from a stored procedure? I'm doing something like:
Connection connection = dataSource.getConnection()
CallableStatement proc = connection.prepareCall("{ call dbo.mySproc() }");
proc.execute();
Should I be using execute()? executeQuery()? executeUpdate()? None of these seem to return a return value by default but I'm not really sure how to get to it.
EDIT 1: To be clear, I know how to call stored procedures. This question is specifically about how to get the RETURN VALUE (as opposed to a Result Set). The Return Value is an integer that is usually generated when you execute a query with no Result Set or if you specifically state something like RETURN 0 in your SQL.
EDIT 2: executeUpdate() returns an int but this int is not the same as the Return Value. Also, an OUT parameter is not the same as a return value.
Bozho's 2nd revised answer was close but not quite there. It did lead me to the answer though.
Taking the code example I started with we end up with:
CallableStatement proc = connection.prepareCall("{ ? = call dbo.mySproc() }");
proc.registerOutParameter(1, Types.INTEGER);
proc.execute();
int returnValue = proc.getInt(1);
The key pieces here are the "? =" in front of the "call" in the prepareCall function which sets up a place for the return value and the registerOutputParameter. It has to be registered as an Integer, as the return value is always an int (at least in SQL Server, maybe it's different in other DBs). You therefore have to get it using getInt. I tested this method and it does work.
c.prepareCall("? = ..");
cs.execute();
String returnedValue = cs.getString(1);
(or the method of the appropriate type. You can use getObject alternatively)
From an old getting started tutorial
the getXXX methods in CallableStatement retrieve values from the OUT parameters and/or return value of a stored procedure.
(Btw, the links that were provided by Umesh had this sort of information.)
Related
I am trying to call a Procedure from a package from my java application but receive an error. The code is set up like so...
------Java-----
Connection = conn;
String call_code="{? = call MY_PROCEDURE.Process_vale(?,?,?)}";
CallableStatement Process_cs=conn.prepareCall(call_code);
String bValue= "12345";
Process_cs.setString(1, bValue);
Process_cs.registerOutParameter(2, Types.INTEGER);
Process_cs.registerOutParameter(3, Types.VARCHAR);
Process_cs.execute();
The Procedure is setup like:
PROCEDURE Process_value (bValue VARCHAR2, PN_CD OUT NUMBER, PN_MSG OUT VARCHAR2).....
The Error I see is:
java.sql.SQLException: Missing IN or OUT parameter at index:: 4
I am curious as to why it mentions an index of 4, when the Procedure only has 3 parameters, I believe I am missing a critical fact here.
You have done some serious mistakes here. First Since you are calling a procedure you wont get any return value, only functions can have return values. So you have to call the procedure as follows.
String call_code="{call MY_PROCEDURE.Process_vale(?,?,?)}";
You could be successfully execute this if your procedure first parameter is IN type and other two parameters are OUT type.
I have some old C code I'm moving to Java and I have to port along existing SQL functions into JDBC. The commands are written like this (two of many examples):
RESULT:=1 + ?
IF ? > 0 THEN RESULT:=0 ELSE RESULT:= 1; END IF;
Those are two examples (separate commands).
Changing the syntax of the commands isn't an option, but some clever runtime replacement is valid. Note the ? are values that will get populated at runtime from other data.
I've tried this as statements, prepared statements, and callable statements, and I can't seem to get the syntax correct for getting "RESULT" back (actually, can't get it to execute() on any statement.
For test purposes I've been trying a simple command of either:
RESULT:=1+2
RESULT:=1+?
Just to see if I can get the type of statement working. But no luck.
The most common answer, from code that otherwise looks reasonable, is this:
String queryString = "declare result integer; begin RESULT:= 1 + 3; ? := RESULT; end";
try (CallableStatement cst = conn.prepareCall(queryString))
{
cst.registerOutParameter(1, Types.INTEGER);
cst.execute();
}
When I run that, on the execute (or executeUpdate, doesn't make a difference) I get back an Oracle 17002/08006 (Size Data Unit mismatch, network issue / invalid connection). But I have to believe that error is somewhat of a red herring, because the connection is definitely valid, and a trivially statement works fine.
Does anyone know the correct JDBC approach to calling that and getting a valid result (out of RESULT)?
I'm using Java 7 and Oracle 11g, if it matters.
Here's an example of calling a stored procedure that accepts an Integer argument and returns a single value (my Java method returns an Object and you can cast it to whatever you like).
public Object getResultFromStoredProcedure(String query,Integer param) {
Object obj=null;
ResultSet rs=null;
PreparedStatement stmt=null;
try{
stmt=conn.prepareStatement(query);
stmt.setInt(1,param);
rs = stmt.executeQuery();
if(rs.next()){
obj=rs.getObject(1);
}
}catch(SQLException e){
//catch exception and process it or log it
}finally{
rs.close();
stmt.close()
}
return obj;
}
Provided that you called your procedure OrclProc, you'd call it thus
String query = "select OrclProc(?) from dual";
Object result = getResultFromStoredProcedure(query, 5);
DELIMITER //
CREATE PROCEDURE temp ( empId INT)
BEGIN
DECLARE var_etype VARCHAR(36);
SELECT
emptype = QOUTE(emptype)
FROM
dms_document
WHERE
id = empid;
SELECT
emptype,
CASE
WHEN emptype = 'P' THEN doctype
ELSE 'No Documents required'
END
FROM
dms_report
WHERE
pilot = 1;
End//
DELIMITER ;
I have created this procedure successfully but when I try to call it, I am getting error 1305 the function database.temp does not exist. I am trying to call using this statement:
SET #increment = '1';
select temp( #increment)
but I get Error, please tell me where I made mistake.
This is how you call it, use use the keyword call and then procedure's name
call procedureName(params);
in call of making an string
String sqlString = "procedureName("+?+")"; //in case of Integers
String sqlString = "procedureName('"+?+"')";//in case of Integers
bring the parameter in prepared statement.
MySQL's documentation on Using JDBC CallableStatements to Execute Stored Procedures explains the necessary steps quite well.
This is what your java code needs to look like:
CallableStatement cStmt = conn.prepareCall("{call temp(?)}");
cStmt.setInt(1, 42); //set your input parameter, empId, to 42.
If you want to work with the rows returned by your stored procedure's query in your Java code, you're also going to need to create an OUT parameter as noted in MySql's documentation page titled, CALL Syntax:
CALL can pass back values to its caller using parameters that are
declared as OUT or INOUT parameters
In order to call your stored procedure from MySQL workbench, use the CALL command. You can call stored procedure by directly setting values for each of the parameters:
SET #increment = 1;
CALL temp(#increment)
Then you simply use the SELECT statement to return the value of your output parameter
SELECT #outParameter
With help setting your output parameters, please read the article MySQL Stored Procedure - SELECT - Example.
Your stored procedure is syntactically wrong, and as mentioned in the comments, you're not using the stored procedure functionality for it's intended use. It's intended to be used for data manipulation not for querying. You should instead consider turning your procedure into a series of prepared statements.
Please let me know if you have any questions!
I have the following stored procedure written in PostgreSQL 9.3 that's working perfectly:
CREATE OR REPLACE FUNCTION getColor(i INT)
RETURNS VARCHAR AS $varColor$
DECLARE varColor varchar;
BEGIN
select color into varColor FROM colors where id = i;
return varColor;
END;
$varColor$ LANGUAGE plpgsql;
In fact, when I execute select getColor(2) in pgAdmin I get the expected value.
I am trying to call it like this from Java (simplified version):
String call = "{ call getColor(?,?) }";
CallableStatement cstmt = connection.prepareCall(call);
cstmt.setInt(1, 2);
cstmt.registerOutParameter(2, java.sql.Types.VARCHAR);
boolean hadResults = cstmt.execute();
The problem is that hadResults is always null.
Any ideas?
Postgresql stored procedures concept is something different than other vendors like Oracle.
Basically what in Oracle is called store procedure in Postgresql can be a function, and to call a function in Java is better to use prepare statements and executeQuery methods like in the following example
String call = "select getColor(?)";
PreparedStatement pstmt = connection.prepareStatement(call);
pstmt.setInt(1,1);
Resultset resultset = pstmt.executeQuery();
Thank you to all the guys who helped in the question comments!
I found out that Java doesn't let ResultSet to be return as a data type. And would like to ask whether is there any better solution to return results after executing query?
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection( "jdbc:mysql://localhost:3306/shopping mall?zeroDateTimeBehavior=convertToNull", "root", "" );
java.sql.Statement stmt = con.createStatement() ;
String query = "SELECT * FROM shops WHERE SHOPNAME LIKE \'%" + shopName + "%\' ORDER BY shopname ASC"; // Select and sort using user input
ResultSet rs = stmt.executeQuery(query) ;
// How to return the result after executing the query?
}
catch ( SQLException err ) {
return null;
}
Don't mind the return null; part. Was testing something. Basically this is my current code for now. How can I return the result after executing query?
You need to provide better context for the error. Is this, for example, a JAX-WS web service endpoint? Anyway, as stated in the trace, your error is a web service error--not a JDBC error. This error can happen for many reasons--usually related to something wrong with the way you are defining the API to your service.
You are certainly allowed to return a ResultSet from a method even if that is a very bad idea, especially from a web service endpoint. A ResultSet can't be serialized into a SOAP message. More generally, to return a ResultSet betrays implementation details to the callers of the method. Why should they know you are using JDBC? Or even that you are talking to a relational (or any) database at all?
The better approach is to populate a model object relevant to your domain with the data in the ResultSet, and that object will be serialized to SOAP via JAXB or whatever you use. Or maybe you just return some text from the database, in which case JAX-WS knows what to do.
Also, make sure you do something with SQLException so you can trace the cause of your actual JDBC errors.
You write a method to retrieve info from a database, where should the data be processed and put into a model class? If you want code that is loosely coupled, then 98% of the time you would process the result set within the same method.
What happens if the query needs to change? You want the changes to be localized into a small of a subset of code as possible.
Take a look at Spring-JDBC JdbcTemplate. This method
List<Map<String, Object>> queryForList(String sql)
returns a List that contains a Map per row. You can use it or make something similar