JPA calling stored procedure with argument - java

I have this procedure in my postgreSQL database:
CREATE OR REPLACE FUNCTION getItemsForCategory(categoryId integer)
RETURNS SETOF ITEM AS $_$
DECLARE
result ITEM;
BEGIN
FOR result IN SELECT *
FROM item it
JOIN item_category itcat ON it.id = itcat.item_id WHERE itcat.category_id = categoryId LOOP
RETURN NEXT result;
END LOOP;
END; $_$ LANGUAGE 'plpgsql';
which works excellent using terminal, but I have trouble with calling it using JPA. Here is my code snippet(4 is value of argument cateforyId):
transactions.begin();
final StoredProcedureQuery storedProcedureQuery = entityManager.createStoredProcedureQuery("getItemsForCategory");
storedProcedureQuery.setParameter(1,4).execute();
final List<ItemEntity> itemEntityList = (List<ItemEntity>) storedProcedureQuery.getResultList();
transactions.commit();
after running code above I receive this error:
Exception in thread "main" java.lang.IllegalArgumentException:
You have attempted to set a parameter at position 1 which does not exist in this query string getItemsForCategory
Has anyone some idea how to set the value of argument correctly? I've also tried to set parameter using 0 instead of 1, calling setParameter with others datatypes of arguments (String,Object) but everytime I am receiving familiar kind of error like the one, which is shown there. Thank you very much

You need to register your parameters, before setting values.
spq.registerStoredProcedureParameter("categoryId", int.class, ParameterMode.IN);
See this link.

Related

CrudRepository - Stored Procedure call is not working because of type/number of argument issue

I have JPA entity as
And then Repository as
Now, when I run it then I get following exception:
And stored procedure is:
It is running against Oracle database. Can someone please help me understand even though I have correct parameter numbers and type, still why I am getting this exception.
Please note: I do not have local environment so I cannot put a sample code, and please do not worry about class/method name, I tried to camouflage them so they may be inconsistent.
There is one more question that suppose I have 2 OUT parameters then how you I create my entity class, with one output parameter I know I can return String (or appropriate return type) but in case of 2 OUT parameters I do no know how to do it? I have read this article but it is only with 1 OUT parameter, and I couldn't find any article or post which explains for 2 OUT parameter. If someone has a code with 2 OUT parameter then it would be helpful.
Please try:
use the exact (db) names of procedure parameters:
#StoredProcedureParameter(name = "tbl_name" ...
#StoredProcedureParameter(name = "p_date" ...
#StoredProcedureParameter(name = "p_message" ...
or (alternatively) omit names completely (rely on position).
From StoredProcedureParameter javadoc:
The name of the parameter as defined by the stored procedure in the database. If a name is not specified, it is assumed that the stored procedure uses positional parameters.
Currently you can't have multiple OUT-parameters using spring-data, but (should be) no problem with standard JPA:
StoredProcedureQuery spq = em.createNamedStoredProcedureQuery("my_proc");
proc.setParameter("p_in", 1);
proc.execute();
Integer res1 = (Integer) proc.getOutputParameterValue("out1");
Integer res2 = (Integer) proc.getOutputParameterValue("out2");
see also: Spring Data JPA NamedStoredProcedureQuery Multiple Out Parameters

How to pass null to SQL parameter in java?

I have a scenario where in i have to pass null to a SQL parameter through java but i am getting SQLGrammarException. If i am passing some value it works fine. Please guide if i am wrong somewhere.
Below is my code:
StringBuffer query;
query = new StringBuffer(
"SELECT * "+
"FROM table(package.func(travel_type => travel_search_type("+
"travel_place_no => :travelPlaceNo"+
")))" );
Query query1 = em.createNativeQuery(query.toString());
query1.setParameter("travelPlaceNo",null);
searchresults = query1.getResultList();
Exception:
org.hibernate.exception.SQLGrammarException
This is what i do through SQL Developer and it works fine:
SELECT *
FROM table(package.func(travel_type => travel_search_type(
travel_place_no => NULL))) ;
Please guide.
While calling the 2 argument signatures of the method, null is not an allowed value. You can use, instead, the 3 argument signature setParameter(String name,
Object val,
Type type) specifying the data type and it should work.
EDIT:
Ok, I see there is also another problem: even if the replacemente worked, what you are trying to execute is a >= NULL. In this case, I'm afraid that you are going to have to handle mannually the StringBuffer creation. Maybe just force an always false condition without parameters if its null, like `1!=2', and otherwise just handle it as you are doing on your sql example (write mannually 'NULL' instead of the parameter placeholder).

Invoking procedure defaults without binding values to parameters in Jdbc

I am trying to call a PL/SQL procedure which has defaults defined for some of its parameters. I am doing this using CallableStatement in JDBC.
This procedure has a large number of parameters with defaults defined. I do not want to explicitly set the defaults in the Java code. Doing this would make maintaining the code harder. If the PL/SQL code changes , would have to make the same changes in the Java code too.
Is it possible to accomplish this in JDBC ? For instance just bind values to the parameter you are interested in and ignore the rest.
I tried this on the following sample procedure :
-- PURPOSE: Takes a parameter which has defaults set. Returns the value of the same parameter
-- Example of: FUNCTION that takes a parameter with DEFAULT values
FUNCTION handle_defaults(empId IN NUMBER DEFAULT 20 , empCity IN VARCHAR2) RETURN NUMBER IS
BEGIN
RETURN empId;
EXCEPTION
WHEN others THEN
dbms_output.put_line('Error!');
END handle_defaults;
Here is the relevant portions of the code (NOTE: Have stripped off the try catch block , cleaning up of database resources etc for sake of readability)
// Create a database connection
conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
// Create a query string
String queryStr = "{ ? = call HR.EMP_PKG.handle_defaults( ? , ? ) }";
// Create a Callable Statements
callStmt = conn.prepareCall(queryStr);
// Bind values to the IN parameter
callStmt.setString(3, "Mumbai");
// Register OUT parameter
callStmt.registerOutParameter(1, java.sql.Types.NUMERIC);
// Execute the Callable Statement
callStmt.execute();
// Retrieve the value of the OUT parameter
parameterValue = callStmt.getInt(1);
System.out.println("Value returned : " + parameterValue);
I get the following error:
Exception occured in the database
java.sql.SQLException: Missing IN or OUT parameter at index:: 2
Database error code: 17041
As a desperate attempt I also tried to pass Nulls for those parameters. Just included the following line:
callStmt.setNull(2, java.sql.Types.NUMERIC);
I get the following result:
Value returned : 0
That makes sense bcoz setNull supplies SQL Null to the parameter.
I am using Oracle 11g and Oracle 12c Jdbc Driver Version 12.1.0.2.
I don't think there's a simple answer to this question, and that's not because of JDBC, but because of Oracle.
Put simply, the only way I know of calling a procedure and using the default value for a parameter is to not specify the parameter when you call the procedure.
If you are writing
String queryStr = "{ ? = call HR.EMP_PKG.handle_defaults( ? , ? ) }";
you are always specifying both parameters, so you can never use the default value for one of them. If you only want to specify one of them and use the default for the other, write:
String queryStr = "{ ? = call HR.EMP_PKG.handle_defaults( empCity => ? ) }";
In this case you need to specify the parameter name in the call, as the first parameter is the optional one. If the second parameter was optional instead, the parameter name can be dropped.
Unfortunately, this becomes quite complicated for your real procedure with lots of parameters. What I would do would be to:
Use a StringBuilder to build up the procedure call string.
Run through the parameters, adding paramName => ? parts to it for each parameter you have a value for. Ensure the parts are separated by commas.
Prepare a CallableStatement using the output of the StringBuilder.
Run through the parameters again and call various setString/setInt/setDate/etc. methods on the CallableStatement for each parameter you have a value for.

#Resolved - Positional parameter does not exist in query // stored function call

I have this method to call a stored function from ORACLE, in java (spring) - using entity manager + createNativeQuery ..
(...)
String set_professional = "{? = call
pk_backoffice.set_professional(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?}";
//32 parameters IN
query = entity.createNativeQuery(set_professional);
(...)
And everytime I try to test it, it shows:
Positional parameter does not exist: 31 in query: {? = call (...)
But do I have something at position 31..it exists..
query.setParameter(31, prof.getFax()); // fax
Also, I started the parameters at 1 cause in previous exceptions it said it was 1-based
I've tried with a string and a null value instead of the get, still the same outcome..
About the query, I also counted the ? many times, so I'm sure it has 32 (for parameters) + 1(return - first ?)...
Can anyone help?
Found a solution, I replaced all ? for variables, even the first one, and the error disappeared.

Use NamedParameterJdbcTemplate to update array field

I have a double precision array field dblArrayFld in a table myTable and I'd like to update it using Spring's NamedParameterJdbcTemplate (I'm using Postgres).
I'm running code like this:
SqlParameterSource params = (new MapSqlParameterSource())
.addValue("myarray", myDblArrayListVar)
.addValue("myid", 123);
namedJdbcTemplate.update("UPDATE myTable SET dblArrayFld = :myarray WHERE idFld = :myid", params);
This returns an error that reads syntax error at or near "$2"
I'm assuming my syntax on :myarray is at fault here. I've also tried encasing :myarray in the following ways:
dblArrayFld={:myarray}
dblArrayFld={ :myarray }
dblArrayFld=[:myarray]
dblArrayFld=ARRAY[:myarray]
dblArrayFld=(:myarray)
What's the correct syntax here?
Wehn you try to bind Collection or array as named parameter, NamedParameterJdbcTemplate explodes the appropriate named parameter in your statement into a number of positional parameters matching the length of your array / collection. This is useful for WHERE column IN (:param) statements, but is not going to work in this case.
In order to set an actual Postgres array you have to supply your parameter as java.sql.Array. You can create its instance using Connection#createArrayOf() method.

Categories

Resources