What is Ordinal binding and Named binding in JDBC - java

What is Ordinal binding and Named binding in JDBC?
while calling a PL/SQL procedure i am getting an exception
java.sql.SQLException: operation not allowed: Ordinal binding and Named binding cannot be combined!

In Oracle, for example, you can write a stored procedure with PL/SQL code like:
CREATE PROCEDURE remove_emp (employee_id NUMBER) AS
tot_emps NUMBER;
BEGIN
DELETE FROM employees
WHERE employees.employee_id = remove_emp.employee_id;
tot_emps := tot_emps - 1;
END;
/
When you call this from Java, you use code like:
CallableStatement cs = conn.prepareCall("{call remove_emp(employee_id)}");
cs.setInt(1, 42); // ordinal binding, or
cs.setInt("employee_id", 42); // named binding
With only one argument, the choice doesn't matter. However, you can't mix techniques.
CallableStatement cs = conn.prepareCall("{call xyzzy(plugh, bedquilt)]");
cs.setInt(1, 42); // ordinal binding, and
cs.setInt("plugh", 1729); // named binding
cs.executeQuery(); // throws

Ordinal means by index. Named means by name.
Google search reveals that this could come up in a number of ways to misuse the API, so it's impossible to guess which one you fell into without seeing your code.

Related

Execute multi-line PostgreSQL script containing stored procedure call with IN/INOUT Parameters using java

I have a special case, in which the following PostgreSQL script is required to be called from java:
do
$$
DECLARE
xx VARCHAR(200);
xy VARCHAR(200);
xz VARCHAR(200);
yy VARCHAR(200);
BEGIN
xx := ?;
xy := ?;
call database_procedure(yy, yz, xx, xy);
? := yy;
? := yz;
END;
$$
This script is passed to CallableStatement in the following way, and the Input/Output parameters are binded with the callable statement.
CallableStatement cs = pgConn.prepareCall(sqlScript);
cs.setString(1,"param1");
cs.setString(2,"value2");
cs.registerOutParameter(3, Types.VARCHAR);
cs.registerOutParameter(4, Types.VARCHAR);
I get the issue on the line
cs.setString(1,"param1");
Issue: org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0.
Upon research i have found that, this issue is because the cs.setString is unable to find question mark(or parameter place holder).
Also, When i try simple query as following, it works.
CallableStatement cs = pgConn.prepareCall("call database_procedure(?,?,?,?)");
But according to my current scenario, I need a solution to executing the whole script as i mentioned, instead of only one call, because in different scenarios we are assigning values to out parameters based on the data returned by the procedure and so on.
Kindly help, so that, somehow the IN/INOUT parameters are passed to the sql script mentioned above.

Java PreparedStatement: any way to use indexed or named parameters? [duplicate]

I have a insert if not exists query as below.
BEGIN
IF NOT EXISTS (SELECT * FROM tbl_sampleTable WHERE name = ? or subject = ?)
BEGIN
INSERT INTO tbl_sampleTable VALUES (?,?)
END
END
I am executing the above query with JDBC PreparedStatement as below
pst.setString(1, name);
pst.setString(2, subject);
pst.setString(3, subject);
pst.setString(4, name);
pst.executeUpdate();
I am getting these name and subject as method parameters, is there anyway i can provide values for multiple "?" with same parameter as they are same, instead of mentioning them two times each.
Edit: I don't use spring or any other framework, if it is relevant.
JDBC doesn't support named parameters, but Spring JDBC provides this functionality with NamedParameterJdbcTemplate
Just in this case you might use SQL variables. It is not a general solution.
And also many SQL vendor specific variants know such insert-when-not-exists constructs, not needing such archaic code.
BEGIN
DECLARE #MyName varchar(100);
DECLARE #MySubject varchar(100);
SET #MyName = ?;
SET #MySubject = ?;
IF NOT EXISTS (SELECT * FROM tbl_sampleTable WHERE name = #MyName OR subject = #MySubject)
BEGIN
INSERT INTO tbl_sampleTable(subject, name) VALUES (#MySubject, #MyName)
END
END
You need to add some wrapper, without using Spring (NamedParameterJdbcTemplate) you can try other as HTTP-RPC framework
The org.httprpc.sql.Parameters class provided by the HTTP-RPC framework brings named parameter support to JDBC. The parse() method of this class is used to create a Parameters instance from a JPA-like SQL query; for example:
SELECT * FROM user WHERE first_name LIKE :pattern or last_name LIKE :pattern
It takes a string or reader containing the query text as an argument:
Parameters parameters = Parameters.parse(sqlReader);
The getSQL() method of the Parameters class returns the processed query in standard JDBC syntax. This value can be used in a call to Connection#prepareStatement():
PreparedStatement statement = connection.prepareStatement(parameters.getSQL());
Parameter values are specified via the put() method:
parameters.put("pattern", pattern);
The values are applied to the statement via the apply() method:
parameters.apply(statement);
Usefull trick in this situation is to declare variables.
You bind the values to the variables only once and you can use them several times in your PL/SQL block.
DECLARE
l_name tbl_sampleTable.name%TYPE := ?;
l_subject tbl_sampleTable.subject%TYPE := ?;
BEGIN
IF NOT EXISTS (SELECT * FROM tbl_sampleTable WHERE name = l_name or subject = l_subject )
BEGIN
INSERT INTO tbl_sampleTable (name,subject)
VALUES (l_name ,l_subject )
END
END

PreparedStatement,using one parameter for multiple "?"

I have a insert if not exists query as below.
BEGIN
IF NOT EXISTS (SELECT * FROM tbl_sampleTable WHERE name = ? or subject = ?)
BEGIN
INSERT INTO tbl_sampleTable VALUES (?,?)
END
END
I am executing the above query with JDBC PreparedStatement as below
pst.setString(1, name);
pst.setString(2, subject);
pst.setString(3, subject);
pst.setString(4, name);
pst.executeUpdate();
I am getting these name and subject as method parameters, is there anyway i can provide values for multiple "?" with same parameter as they are same, instead of mentioning them two times each.
Edit: I don't use spring or any other framework, if it is relevant.
JDBC doesn't support named parameters, but Spring JDBC provides this functionality with NamedParameterJdbcTemplate
Just in this case you might use SQL variables. It is not a general solution.
And also many SQL vendor specific variants know such insert-when-not-exists constructs, not needing such archaic code.
BEGIN
DECLARE #MyName varchar(100);
DECLARE #MySubject varchar(100);
SET #MyName = ?;
SET #MySubject = ?;
IF NOT EXISTS (SELECT * FROM tbl_sampleTable WHERE name = #MyName OR subject = #MySubject)
BEGIN
INSERT INTO tbl_sampleTable(subject, name) VALUES (#MySubject, #MyName)
END
END
You need to add some wrapper, without using Spring (NamedParameterJdbcTemplate) you can try other as HTTP-RPC framework
The org.httprpc.sql.Parameters class provided by the HTTP-RPC framework brings named parameter support to JDBC. The parse() method of this class is used to create a Parameters instance from a JPA-like SQL query; for example:
SELECT * FROM user WHERE first_name LIKE :pattern or last_name LIKE :pattern
It takes a string or reader containing the query text as an argument:
Parameters parameters = Parameters.parse(sqlReader);
The getSQL() method of the Parameters class returns the processed query in standard JDBC syntax. This value can be used in a call to Connection#prepareStatement():
PreparedStatement statement = connection.prepareStatement(parameters.getSQL());
Parameter values are specified via the put() method:
parameters.put("pattern", pattern);
The values are applied to the statement via the apply() method:
parameters.apply(statement);
Usefull trick in this situation is to declare variables.
You bind the values to the variables only once and you can use them several times in your PL/SQL block.
DECLARE
l_name tbl_sampleTable.name%TYPE := ?;
l_subject tbl_sampleTable.subject%TYPE := ?;
BEGIN
IF NOT EXISTS (SELECT * FROM tbl_sampleTable WHERE name = l_name or subject = l_subject )
BEGIN
INSERT INTO tbl_sampleTable (name,subject)
VALUES (l_name ,l_subject )
END
END

Reading DBMS_Ouptut after Executing PLSQL from jdbc

I need to execute an Oralce PL/SQL statement using jdbc, but I'm struggling on how to extract the data.
Here is my statement
DECLARE
l_xmltype XMLTYPE;
l_ctx dbms_xmlgen.ctxhandle;
BEGIN
l_ctx := dbms_xmlgen.newcontext('select * from myTable where rownun < 10;);
dbms_xmlgen.setrowsettag(l_ctx, 'My_DATA');
dbms_xmlgen.setrowtag(l_ctx, 'My_Element');
l_xmltype := dbms_xmlgen.getXmlType(l_ctx) ;
dbms_xmlgen.closeContext(l_ctx);
dbms_output.put_line(l_xmltype.getClobVal);
dbms_output.get_lines(?, l_xmltype);
End;
And my code
CallableStatement cs = connection.prepareCall(plsql);
cs.registerOutParameter(1, Types.ARRAY,"DBMSOUTPUT_LINESARRAY");
cs.execute();
Array array = null;
array = cs.getArray(1);
Stream.of((Object[]) array.getArray())
.forEach(System.out::println);
And I'm getting the error
java.sql.SQLException: ORA-06550: line 1, column 380: PLS-00306: wrong
number or types of arguments in call to 'GET_LINES'
I'm not an expert in PL/SQL nor jdbc so I'm struggling to find a solution.
The second argument of GET_LINES is a number, not an XMLTYPE. Change your call to something like:
dbms_output.get_lines(?, 50);
I've also shown a more complete example on how to do this in a similar question. Note that you also have to add the following call first, to enable dbms_output collection:
dbms_output.enable();
Note that in case you're using jOOQ, you can automatically fetch server output on any statement.

How to call procedure in mysql workbench

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!

Categories

Resources