calling Stored Procedure in Java - java

I have a SP:
ALTER PROCEDURE [dbo].[auth_user]
#username nchar(50),
#password nchar(50)
AS BEGIN
DECLARE #response AS bit = 0;
UPDATE dbo.Users
SET #response = 1
WHERE Username = #username
AND Password = #password
RETURN #response
END
I try to get return value from SP in Java
Connection connection = null;
CallableStatement storedProcedure = null;
ResultSet resultSet = null;
...
connection = Shop.OpenConnection();
storedProcedure = connection.prepareCall("{call auth_user(?, ?)}");
storedProcedure.setString(1, UsernameField.getText());
storedProcedure.setString(2, PasswordField.getText());
resultSet = storedProcedure.executeQuery(); //Error
if (resultSet.next()) {
JOptionPane.showMessageDialog(null, "Correct username and password");
MainFrame frame = new MainFrame();
frame.setVisible(true);
} else {
JOptionPane.showMessageDialog(null, "Wrong username or password");
}
I need to get return value(0 or 1), but I get error:
com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.

I did it and I want to share with you this information.
connection = Shop.OpenConnection();
storedProcedure = connection.prepareCall("**{? = call auth_user(?, ?)}**");
storedProcedure.setString(2, UsernameField.getText());
storedProcedure.setString(3, PasswordField.getText());
storedProcedure.registerOutParameter(1, Types.INTEGER);
storedProcedure.execute();
System.out.println(storedProcedure.getInt(1));
I changed string of call SP -> {? = call auth_user(?, ?)}
and declared each parameter with its number. That is, the return value is 1, the passed parameter is 2, and the passed parameter is 3

In your SP, you declare #response as bit but don't give it a default value. Bits can be 0, 1, or NULL. #response is set to NULL.
In the update, you set it to 1 only when username and password match. If they don't match, #response is still NULL.
This should fix it.
DECLARE #response AS bit = 0;

Related

Parameter #p_appraisal_period_id was not defined for stored procedure sp_StatusReport_GoalCompletionPercentageBySup [duplicate]

I am trying to execute a stored procedure using SQL Server JDBC in a method:
//Connection connection, String sp_name, Map<String, Object>params input to the method
DatabaseMetaData dbMetaData = connection.getMetaData();
HashMap<String, Integer> paramInfo = new HashMap<String, Integer>();
if (dbMetaData != null)
{
ResultSet rs = dbMetaData.getProcedureColumns (null, null, sp_name.toUpperCase(), "%");
while (rs.next())
paramInfo.put(rs.getString(4), rs.getInt(6));
rs.close();
}
String call = "{ call " + sp_name + " ( ";
for (int i = 0; i < paramInfo.size(); i ++)
call += "?,";
if (paramInfo.size() > 0)
call = call.substring(0, call.length() - 1);
call += " ) }";
CallableStatement st = connection.prepareCall (call);
for (String paramName: paramInfo.keySet()){
int paramType = paramInfo.get(paramName);
System.out.println("paramName="+paramName);
System.out.println("paramTYpe="+paramType);
Object paramVal = params.get(paramName);
st.setInt(paramName, Integer.parseInt(((String)paramVal))); //All stored proc parameters are of type int
}
Let say the stored procedure name is ABC and parameter is #a.
Now DatabaseMetaData returns column name #a but setting st.setInt("#a",0) returns following error:
com.microsoft.sqlserver.jdbc.SQLServerException: Parameter #a was not defined for stored procedure ABC.
Instead, I tried this: st.setInt("a",0) and it executed perfectly.
Now the problem is I have to set the parameters dynamically as I have too many stored procedures and too many parameters but jdbc is giving error.
Edit 1:
As pointed out in one answer that my question is a duplicate of: Named parameters in JDBC, I would like to explain that the issue here is not named parameters or positional ones, rather it is about JDBC not handling the SQL server parameters itself properly or my making some error while invoking it.
Update 2017-10-07: The merge request to fix this issue has been accepted, so this should no longer be a problem with versions 6.3.4 and later.
Yes, it is an unfortunate inconsistency that for mssql-jdbc the parameter names returned by DatabaseMetaData#getProcedureColumns do not match the names accepted by CallableStatement#setInt et. al.. If you consider it to be a bug then you should create an issue on GitHub and perhaps it will be fixed in a future release.
In the meantime, however, you'll just have to work around it. So, instead of code like this ...
ResultSet rs = connection.getMetaData().getProcedureColumns(null, "dbo", "MenuPlanner", null);
while (rs.next()) {
if (rs.getShort("COLUMN_TYPE") == DatabaseMetaData.procedureColumnIn) {
String inParamName = rs.getString("COLUMN_NAME");
System.out.println(inParamName);
}
}
... which produces ...
#person
#food
... you'll need to use code like this ...
boolean isMssqlJdbc = connection.getClass().getName().equals(
"com.microsoft.sqlserver.jdbc.SQLServerConnection");
ResultSet rs = connection.getMetaData().getProcedureColumns(null, "dbo", "MenuPlanner", null);
while (rs.next()) {
if (rs.getShort("COLUMN_TYPE") == DatabaseMetaData.procedureColumnIn) {
String inParamName = rs.getString("COLUMN_NAME");
if (isMssqlJdbc && inParamName.startsWith("#")) {
inParamName = inParamName.substring(1, inParamName.length());
}
System.out.println(inParamName);
}
}
... which produces ...
person
food

The executeQuery method must return a result set issue

i have an issue where i trying to use a sp but i be getting a
The executeQuery method must return a result
and if i use cs.execute(); with ResultSet rs = cs.getResultSet(); instead i get a nullpointer on if(rs.next())
protected String doInBackground(String...params) {
if (userid.trim().equals("") || password.trim().equals("")) z = getString(R.string.wrong_user);
else {
try {
Connection con = connectionClass.CONN();
if (con == null) {
z = getString(R.string.connection_error);
} else {
String query = "{?=call [system].[usp_validateUserLogin](?,?,?,?,?)}";
CallableStatement cs = con.prepareCall(query);
cs.registerOutParameter(1,Types.INTEGER);
cs.setString(2, userid);
cs.setString(3, password);
cs.setInt(4, 72);
cs.setNull(5, Types.BIT);
cs.registerOutParameter(6, Types.VARCHAR);
cs.execute();
boolean firstResultIsResultSet = cs.execute();
if (firstResultIsResultSet) {
ResultSet rs = cs.getResultSet();
// process result set
}
}
}
if (rs.next()) {
z = getString(R.string.login_succes);
isSuccess = true;
} else {
z = getString(R.string.Invalid_Credentials);
isSuccess = false;
}
}
} catch (Exception ex) {
isSuccess = false;
z = getString(R.string.Exceptions);
}
}
return z;
}
SP:
ALTER PROCEDURE [system].[usp_validateUserLogin]
#p_Login NVARCHAR ( 50 ),
#p_Password NVARCHAR ( 32 ),
#p_CompanyID INT,
#p_OutDetails BIT = 1,
#p_AuthenticationTicket VARCHAR(200) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #errNo INT,
#recCount INT,
#res INT
SELECT u.*
INTO #TMPLOGIN
FROM SYSTEM.[user] AS u WITH ( NOLOCK )
WHERE ( u.login = #p_Login )
AND ( u.company_id = #p_CompanyID )
AND ( PWDCOMPARE (#p_Password, u.passwd) = 1 )
AND ( u.status = 0 ) --Active
SELECT #errNo = ##ERROR,
#recCount = ##ROWCOUNT
IF ( #errNo <> 0 )
BEGIN
RETURN 1010
END
IF ( #recCount = 1 )
BEGIN
DECLARE #userID INT
SELECT #userID = id
FROM #TMPLOGIN
EXEC #res = SYSTEM.USP_RENEWAUTHENTICATIONTICKET
#p_DoerTicket = '',
#p_AuthenticationTicket = #p_AuthenticationTicket OUTPUT,
#p_UserID = #userID,
#p_CompanyID = #p_CompanyID
IF ( #res <> 0 )
RETURN #res
END
--SET #p_AuthenticationTicket = 'TESTAUTHENTICATIONTICKET0123456789'
IF ( #p_OutDetails = 1 )
BEGIN
SELECT *
FROM #TMPLOGIN
END
RETURN 0
END
Warning: this answer was written without access to a SQL Server instance, so it might not be correct, I hope it will help you. I'll try to update it later when I do have access to an SQL Server system.
The problem seems to be is that you have three different ways of getting values from this stored procedure. You have a return value, an OUTPUT parameter and a result set. If the result set is produced depends on the logic of your stored procedure, so you must be prepared to handle its absence.
First of all, to get the return value of the stored procedure, you must use:
String query = "{?=call [system].[usp_UserLogin(?,?,?,?,?)}";
Where the ?= is the return value.
This also has an effect on the the index of the various parameters. It may also be necessary to explicitly register the first (return) parameter as an out parameter.
Then you need to execute the stored procedure and be prepared to handle the absence of a result set:
boolean firstResultIsResultSet = cs.execute();
if (firstResultIsResultSet) {
ResultSet rs = cs.getResultSet();
// process result set
}
Note that if you would have multiple result sets and also update counts, this would get even more complicated.
You should be able to get the return value using cs.getInt(1), although I'm not 100% sure if you can get it before checking and processing the result set. On this the Javadoc for CallableStatement says:
For maximum portability, a call's ResultSet objects and update counts should be processed prior to getting the values of output parameters.

Getting "java.sql.SQLException: Values not bound to statement" exception

I was trying to make a program which consists of connecting an user by a login system with SQL, then if the credentials are good the user is redirected to an another frame.
But I had a problem, I want to have some information in the SQL base, so I have tried to use while loop and it was working, but after I encountered an error :
java.sql.SQLException: Values not bound to statement
See the following code :
String pseudo2 = null;
String rank2 = null;
try {
String searchname2 = "select * from AdminsInfos where pseudo=?";
PreparedStatement name2 = connection.prepareStatement(searchname2);
ResultSet rspseudo2 = name2.executeQuery();;
while (rspseudo2.next())
{
pseudo2 = rspseudo2.getString("Pseudo");
rank2 = rspseudo2.getString("Rank");
}
} catch (Exception e2) {
e2.printStackTrace();
}
JOptionPane.showMessageDialog(null, "Username and password are correct, connection Admin !");
frame.setVisible(false);
new LoginMain().setVisible(true);
LoginMain.usernameField.setText(pseudo2);
LoginMain.ranklabel.setText("Rank : " + rank2);
and you can check the SQL base too by the following picture :
sql base
Can someone help me?
Since you have a bound variable you need to set the value before executing the statement.
for example , if psuedo is of type String then you will be doing something like below.
String searchname2 = "select * from AdminsInfos where pseudo=?";
PreparedStatement name2 = connection.prepareStatement(searchname2);
name2.setString(1,"value");
ResultSet rspseudo2 = name2.executeQuery();
where first parameter in the setString means you want to set the first value for the bound variable.

How to access the procedure that return setof refcursor from PostgreSQL in Java?

Need to access a procedure that return setof refcursor from PostgreSQL.
I am able to access the first object but not rest of object not rest of objects.
con.setAutoCommit(false);
try (CallableStatement proc =
con.prepareCall("{ ? = call usp_sel_article_initialdata_new1() }")) {
proc.registerOutParameter(1, Types.OTHER);
proc.execute();
ResultSet results = (ResultSet) proc.getObject(1);
while (results.next()) {
System.out.println("Result Id" + results.getString(1));
System.out.println("Results Name" + results.getString(2));
}
This give me the first refcursor values but when i try to use second refcursor it give me error
I use this line:
proc.registerOutParameter(2, Types.OTHER);
It is giving errors . Also tried:
proc.registerOutParameter(1, Types.REF);
This also not work.
Procedure Example is:
CREATE OR REPLACE FUNCTION usp_sel_article_initialdata_new1()
RETURNS SETOF refcursor AS
$BODY$
Declare swv_refcur refcursor;
swv_refcur2 refcursor;
DECLARE r record;
BEGIN
open SWV_RefCur for Select OM.opID as ID,OM.OperatorName as Name from operator
AS OM (OPid bigint,OperatorName character varying(100),status boolean)
where OM.status = true
order By OperatorName;
return next SWV_RefCur;
open SWV_RefCur2 for Select CC.cirid as ID,CC.cirnm as Name from circle
AS CC (cirid bigint,cirnm character varying(100),status boolean)
where Status = true and cirid not in(28,31)
order by cirnm;
return next SWV_RefCur2;
Please help me how to access second object.
returns setof refcursor means you get a regular ResultSet where each "row" contains another ResultSet when calling getObject():
The following works for me:
ResultSet rs = stmt.executeQuery("select * from usp_sel_article_initialdata_new1()");
if (rs.next())
{
// first result set returned
Object o = rs.getObject(1);
if (o instanceof ResultSet)
{
ResultSet rs1 = (ResultSet)o;
while (rs1.next())
{
int id = rs1.getInt(1);
String name = rs1.getString(2);
.... retrieve the other columns using the approriate getXXX() calls
}
}
}
if (rs.next())
{
// process second ResultSet
Object o = rs.getObject(1);
if (o instanceof ResultSet)
{
ResultSet rs2 = (ResultSet)o;
while (rs2.next())
{
......
}
}
}
From within psql you can also use select * from usp_sel_article_initialdata_new1() you just need to use FETCH ALL afterwards. See the manual for an example: http://www.postgresql.org/docs/current/static/plpgsql-cursors.html#AEN59018
postgres=> select * from usp_sel_article_initialdata_new1();
usp_sel_article_initialdata_new1
----------------------------------
<unnamed portal 1>
<unnamed portal 2>
(2 rows)
postgres=> fetch all from "<unnamed portal 1>";
?column?
----------
1
(1 row)
postgres=> fetch all from "<unnamed portal 2>";
?column?
----------
2
(1 row)
postgres=>
(I created a dummy function for the above example that only returns a single row with the value 1 for the first cursor and 2 for the second cursor)
Edit:
In order for this to work, this needs to be run inside a transaction. Therefor autocommit must be turned off:
connection.setAutoCommit(false);
When i call stored procedures i use EntityManager.
Below I attached simple example:
//StoredProcedureQuery storedProcedure = entityManager.createStoredProcedureQuery("[database_name].[schema_name].[procedure_name]");
StoredProcedureQuery storedProcedure = entityManager.createStoredProcedureQuery("[Mydatabase].[dbo].[process_user]");
//registering INPUT parameters
storedProcedure.registerStoredProcedureParameter("Id",Integer.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("Name",String.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("UserType",Integer.class, ParameterMode.IN);
//registering OUTPUT parameters
storedProcedure.registerStoredProcedureParameter("ErrorCode",Integer.class, ParameterMode.OUT);
storedProcedure.registerStoredProcedureParameter("ErrorMessage",String.class, ParameterMode.OUT);
//setting INPUT parameters
storedProcedure.setParameter("Id", 12345);
storedProcedure.setParameter("Name", "Mick");
storedProcedure.setParameter("UserType", 1);
//executing procedure
storedProcedure.execute();
//getting results
Integer errorCode = (Integer) storedProcedure.getOutputParameterValue("ErrorCode");
String errorMessage = (String) storedProcedure.getOutputParameterValue("ErrorMessage");
Hope this will help
This worked for me in following version
springframework-version :- 4.2.1.RELEASE
hibernate.version:- 5.0.1.Final
postgresql.version :- 9.1-901-1.jdbc4
// Call the stored procedure
ProcedureCall procedureCall = getSession().createStoredProcedureCall("get_all_matching_email_profile");
// Register the output parameter, postgres support ref_cursor as first parameter only, so don't change it
procedureCall.registerParameter(1, void.class, ParameterMode.REF_CURSOR);
// Inpur parameters
procedureCall.registerParameter(2, BigDecimal.class, ParameterMode.IN);
procedureCall.registerParameter(3, String.class, ParameterMode.IN);
procedureCall.getParameterRegistration(2).bindValue(companyId);
procedureCall.getParameterRegistration(3).bindValue(tempArray[i]);
// Execute the procedure and get the result
ProcedureOutputs procedureOutputs = procedureCall.getOutputs();
ResultSetOutput resultSetOutput = (ResultSetOutput)procedureOutputs.getCurrent();
List results = resultSetOutput.getResultList();
log.info("The result is "+results.size());
for(Integer j=0;j<results.size();j++) {
Object[] objects = (Object[]) results.get(j);
log.info("The result is "+objects.length);
}
This worked for me:
Connection conn = DBConnection.getNMSDBConnection();
conn.setAutoCommit(false);
CallableStatement properCase = conn.prepareCall("{ ? = call data.temperature_raw_data( ?,?,?,? ) }") ;
properCase.registerOutParameter(1, Types.REF_CURSOR);
properCase.setLong(2, startDate);
properCase.setLong(3, endDate);
properCase.setString(4, deviceIp);
properCase.setString(5, customers);
properCase.execute();
ResultSet rs = (ResultSet) properCase.getObject(1);
while (rs.next())
{
HashMap<String, Object> record = new HashMap<>();
record.put("date", rs.getTimestamp(1));
record.put("nodeIp", rs.getString(2));
record.put("avg", rs.getDouble(3));
records.add(record);
}
if you want to write a java code which will call PostgreSQL Stored procedure where
there is an INOUT refcursor.
PostgreSQL SP:
CREATE OR REPLACE PROCEDURE Read_DataDetails(INOUT my_cursor REFCURSOR = 'rs_resultone')
LANGUAGE plpgsql
AS $$
BEGIN
OPEN my_cursor FOR Select * from MyData;
END;
$$;
corresponding java code will be:
connection = getConnection(your connection parameter);
if (connection != null) {
connection.setAutoCommit(false); // This line must be written just after the
//connection open otherwise it will not work since cursor will be closed immediately.
String readMetaData = "CALL Read_DataDetails(?)";
callableStatement = connection.prepareCall(readMetaData);
callableStatement.registerOutParameter(1, Types.REF_CURSOR);
callableStatement.execute();
rs = (ResultSet) callableStatement.getObject(1);
if (rs != null) {
while (rs.next()) {
<Your Logic>
}//end while
}//end if
}//end if

Incomplete ResultSet data

Comment comment;
ArrayList<Comment> commentList = null;
try{
ConnectionFactory myFactory = ConnectionFactory.getFactory();
Connection conn = myFactory.getConnection();
int i = 1; int j = 1; int k = 1;
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM COMMENT WHERE deletestatus = 0 and workid = ?");
PreparedStatement pstmtLName = conn.prepareStatement("SELECT * FROM LEADER WHERE leaderid = ?");
PreparedStatement pstmtMName = conn.prepareStatement("SELECT * FROM MEMBER WHERE memberid = ?");
pstmt.setInt(i++, Integer.parseInt(projid));
ResultSet rs = pstmt.executeQuery();
System.out.print(rs);
commentList = new ArrayList<Comment>();
while(rs.next())
{
comment = new Comment();
comment.setDetails(rs.getString("details"));
comment.setDateadded(rs.getTimestamp("dateadded"));
comment.setUrgency(rs.getInt("urgency"));
if(rs.getInt("leaderid") != 0){
comment.setLeaderid(rs.getInt("leaderid"));
pstmtLName.setInt(j++, rs.getInt("leaderid"));
ResultSet rs2 = pstmtLName.executeQuery();
if(rs2.next()){
comment.setFullname(rs2.getString("firstname") +" " + rs2.getString("lastname"));
}
}
if(rs.getInt("memberid") != 0) {
comment.setMemberid(rs.getInt("memberid"));
System.out.print("in the loop");
pstmtMName.setInt(j++, rs.getInt("memberid"));
ResultSet rs3 = pstmtMName.executeQuery();
if(rs2.next()){
comment.setFullname(rs3.getString("firstname") +" " + rs3.getString("lastname"));
}
}
comment.setProjid(Integer.parseInt(projid));
commentList.add(comment);
}
return commentList;
}
The problem with the code above is that it only gives back the first result of the result set.
When i removed both of the IF clauses in the WHILE(RS.NEXT) clause, it returned all the needed results but incomplete information because what i also need the query inside the if statement.
Please do help if you guys know the exact problem and tell me if you guys need more info. Thank you!
Here, The problem seems at
pstmtLName.setInt(j++, rs.getInt("leaderid"));
pstmtMName.setInt(j++, rs.getInt("memberid"));
The value of j would be increased for each true condition till loop iteration.
Thus,it increases your parameterIndex of prepapred statement.
It should be
pstmtLName.setInt(1, rs.getInt("leaderid"));
pstmtMName.setInt(1, rs.getInt("memberid"));
You have defined int k but did not use it. I assume you wanted to use it to set memberid parameter.
Change
pstmtMName.setInt( j++, rs.getInt( "memberid" ) );
to
pstmtMName.setInt( k++, rs.getInt( "memberid" ) );
and it should be working.
And I wonder why you use i++, j++ and k++ to set the param values of the statement when there is only one parameter marker ? seen in the query. You should directly be using pstObject.setInt( 1, .... Otherwise, if rs fetches more than a record where leaderid != 0 and memberid != 0, they would cause an increment for the marker index, say pstObject.setInt( 2, ..., which is an invalid parameter in your query case and throws and SQLException.
As you are repeatedly using the same pstObject in a while loop, I would like to suggest using pstObject.clearParameters() to clear current parameter values. Though this is optional, in some cases it is useful to immediately release the resources used by the current parameter values.

Categories