wrong number or types of arguments while calling Stored Proc - oracle

I am calling Stored Proc from Spring Data JPA :
Procedure is:
create or replace procedure GET_LATEST_GC (arg1 IN VARCHAR2, res1 OUT VARCHAR2, res2 OUT VARCHAR2)
AS
BEGIN
DELETE FROM GC_T WHERE id = arg1;
COMMIT;
BEGIN
SELECT gc.NAME, s.SIP INTO res1, res2
FROM GC_T gc, STAFF_T s WHERE s.id = gc.id
AND START_TIME = (SELECT MAX(START_TIME) FROM GC_T);
EXCEPTION
WHEN others THEN
res1 := '';
END;
END;
Spring Data JPA code
//Repository
public interface ActiveDao extends JpaRepository<GcT,Integer> {
#Procedure(procedureName="GET_LATEST_GC")
Object[] plus1(#Param("arg1") String arg1);
}
//Entity
#Data
#Entity
#NamedStoredProcedureQuery(name = "GET_LATEST_GC",
procedureName = "GET_LATEST_GC", parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "arg1", type = String.class),
#StoredProcedureParameter(mode = ParameterMode.OUT, name = "res1", type = String.class),
#StoredProcedureParameter(mode = ParameterMode.OUT, name = "res2", type = String.class)})
#Table(schema = "abc", name = "GC_T")
public class GcT implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
private String id;
#Column(name = "NAME")
private String name;
}
//Call
Object[] activeGCInfo =activeDao.plus1(arg);
Procedure is accepting one parameter and I am also passing 1 argument.Then also I am getting this error:
Hibernate: {call GET_LATEST_GC(?,?)}
ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ORA-06550: line 1, column 7:\nPLS-00306: wrong number or types of arguments in call to 'GET_LATEST_GC'\nORA-06550: line 1, column 7:\nPL/SQL: Statement ignored\n
Please let me know where I am doing wrong.
Thank you
Update- Tried to add OUT params also as per suggestion
//Repo
public interface ActiveDao extends JpaRepository<GcT,Integer> {
#Procedure(procedureName="GET_LATEST_GC")
Object[] plus1(#Param("arg1") String arg1,#Param("res1") String res1,#Param("res2") String res2);
}
//Call
Object[] activeGCInfo =activeDao.plus1(arg,"","");
I am sending three args but it is showing me 4 args in error:
Hibernate: {call GET_LATEST_GC(?,?,?,?)} SqlExceptionHelper - ORA-06550: line 1, column 7:\nPLS-00306: wrong number or types of
arguments in call to 'GET_LATEST_GC'\nORA-06550: line 1, column
7:\nPL/SQL: Statement ignored\n

Try changing the result from Object[] to Map<String, Object, along with referencing the proc name with name instead of procedureName. Based on the error, I'm not sure that it will fix it. Spring Data JPA does expect a Map as the return value for multiple output params, so each output param can be found as the key in that Map. But I think the main error is that procedureName maps directly to the db, but name= will map to the correct Entity
//Repo
public interface ActiveDao extends JpaRepository<GcT,Integer> {
#Procedure(name="GET_LATEST_GC")
Map<String, Object> plus1(#Param("arg1") String arg1);
}
//Call
Map<String, Object> activeGCInfo =activeDao.plus1(arg);

Here's what happened:
you declared a procedure with 3 parameters: 1 in and 2 out
you said: "Procedure is accepting one parameter and I am also passing 1 argument"
that was the 1st procedure's parameter (arg1 IN)
it results in "PLS-00306: wrong number or types of arguments"
Of course it does; you need to provide 2 more arguments (datatype should be able to accept VARCHAR2 values returned by the procedure).

Related

How to ignore some columns during inserting date

When you use Android Room auto generated insert method, it pass all values to all columns For example, if you have an entity like below:
#Entity
public class Task {
#PrimaryKey(autoGenerate = true)
public long id;
#NonNull
#ColumnInfo(defaultValue = "Unknown Title")
public String name;
#NonNull
#ColumnInfo(defaultValue = "Does not have any description!")
public String desc;
#ColumnInfo(defaultValue = "false")
public boolean isDone;
}
And you try to insert an empty instance of Task class by:
taskDao.insert(new Task());
It will run a query like this:
INSERT INTO Task (id, name, desc, isDone) values (null, null, null, 0);
that is against of our table structure rules, so we get error:
Caused by: android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: task.name (code 1299 SQLITE_CONSTRAINT_NOTNULL)
While if it use this query:
INSERT INTO Task DEFAULT VALUES;
or
INSERT INTO Task (id) VALUES (null);
SQLite creates a row with all default values, without any errors.
But to ignore null variables in the insert query for using default valuse?
Try this:
#Entity
public class Task {
public String mName = "Unknown Title";
public String mDescription = "Does not have any description!";
public boolean mIsDone = "false";
#PrimaryKey(autoGenerate = true) //must be placed at the end!!
public long id = 0;
}
And create object like this:
Task task = new Task() //all use default values
Task task = new Task(name) //use default values for other fileds
Task task = new Task(name, description) //the order matters, otherwise you need to explicitlty specify the filed, like following
Task task = new Task(mIsDone = true, mName = "Sam")
Room "deaultValue" is not for entity use:
https://developer.android.com/reference/androidx/room/ColumnInfo#defaultValue()
Based on what is written in the Android documentation:
The default value you specify here will NOT be used if you simply insert the Entity with #Insert.
That means there are no simple way but you can do it in some ways:
Assign Variables Values
Assign what you defined as default values in #ColumnInfo, for those variables value, because if you doesn't update those values, the default assignment will be used, as Documentation says:
If you simply insert the Entity with #Insert ... any value assigned in Java/Kotlin will be used.
#Entity
public class Task {
#PrimaryKey(autoGenerate = true)
public long id;
#NonNull
#ColumnInfo(defaultValue = "Unknown Title")
public String name = "Unknown Title";
#NonNull
#ColumnInfo(defaultValue = "Does not have any description!")
public String description = "Does not have any description!";
#ColumnInfo(defaultValue = "false")
public boolean isDone; // it doesn't need assignment
// boolean values are false as default
}
Special Query
As Documentation recommend:
Use #Query with an INSERT statement and skip this column there in order to use this default value.
#Query("INSERT INTO task DEFAULT VALUES")
long insert();
or
#Query("INSERT INTO task (id) VALUES (null)")
long insert();
As you told in your question.
Simplified Class (ref)
#Insert(entity = Task.class)
long insert(NewTask task);
#Entity
class NewTask {
int id = 0;
}
it runs
INSERT INTO task (id) VALUES (null);

Unable to Read 2nd Refcursor in a Spring Boot application with Hibernate and Oracle 11g Database

Problem Details
We are working on a Spring Boot application where in we are connecting to Stored Procs (all returning multiple refcursors) using #NamedStoredProcedureQuery for Oracle 11g DB. We are unable to read data from the second cursor at the same time. As soon as we provide the second result class for the 2nd refcursor we are getting an exception titled Invalid Column Name. Reading 1 cursor works fine.
Exception Details
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException:
Error extracting results from CallableStatement Caused by:
java.sql.SQLException: Invalid column name
Implementation Details
STORED PROCEDURE QUERY
#NamedStoredProcedureQuery (
name = "getSP1Data",
procedureName = "package_name",
resultClasses = {Cursor1Response.class, Cursor2Response.class},
parameters = {
#StoredProcedureParameter(type = Integer.class, mode = ParameterMode.IN, name = "in_param_1"),
#StoredProcedureParameter(type = void.class, mode = ParameterMode.REF_CURSOR, name = "cursor_1"),
#StoredProcedureParameter(type = void.class, mode = ParameterMode.REF_CURSOR, name = "curosr_2"),
#StoredProcedureParameter(type = String.class, mode = ParameterMode.INOUT, name = "in_out_param_2") }
)
CURSOR RESPONSE CLASSES
#Entity
public class Cursor1Response {
#Id
#Column(name = "column_name_1")
private Date column1;
#Column(name = "column_name_2")
private Double column2;
}
#Entity
public class Cursor2Response {
#Id
#Column(name = "column_name_1")
private Date column1;
#Column(name = "column_name_2")
private Double column2;
}
DAO LAYER IMPLEMENTATION (FROM WHERE WE ACTUALLY CALL OUR STORED PROC QUERY)
StoredProcedureQuery query = entityManager.createNamedStoredProcedureQuery("getSP1Data");
// Code for setting all in params
query.getResultList(); // While execution of this line it is
throwing the above mentioned exception
Has anyone worked on such scenario and have any ideas how to fix this exception?
I had the same issue. First I tried downgrading the Oracle JDBC driver from 8 to 6 with no results. After that I changed the annotation with a more programmatic stored procedure definition (note: avoid positional parameters, they cause the same problem...):
EntityManager entityManager = Persistence.createEntityManagerFactory("namehere").createEntityManager();
StoredProcedureQuery spq =
entityManager.createStoredProcedureQuery("YOUR.SP.NAME")
.registerStoredProcedureParameter("name1", String.class, ParameterMode.IN)
.registerStoredProcedureParameter("name2", Integer.class, ParameterMode.OUT)
.registerStoredProcedureParameter("name3", String.class, ParameterMode.OUT)
.registerStoredProcedureParameter("name4", void.class,ParameterMode.REF_CURSOR)
.setParameter(SP_PARAM_MSISDN, "paramval");
spq.execute();

Error calling CallableStatement.getMoreResults. Calling Stored Procedure using JPA Repository

I use this page to guide myself on how to do it
https://dzone.com/articles/calling-stored-procedures-from-spring-data-jpa
I need to call a stored procedure in an Oracle DB, using Hibernate and Repositories. My procedure receives 1 IN parameter and 2 OUT parameters, I don't really use the OUT parameters in my application.
My procedure receives this
create or replace procedure PRD_DIC_SISTEMA(P_NRO_EVALUACION number
,P_DICTAMEN out varchar2
,P_RESPUESTA out varchar2) is
My service
public ResultsDTO getSystemEvaluation(Long evaluationCode) throws BusinessException {
ResultsDTO response = new ResultsDTO();
dictaminationOperationRepository.systemDictaminationResults(evaluationCode);
return response;
}
Repository
public interface DictaminationOperationRepository extends CrudRepository<DictaminationOperation,DictaminationOperationPK>{
#Transactional
#Procedure(procedureName="prd_dic_sistema")
void systemDictaminationResults(#Param("p_nro_evaluacion") Long evaluationCode);
}
My bean class
#Entity
#Table(name="WP_EVA_DIC_OPERACIONES")
#JsonInclude(Include.NON_NULL)
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(
name = "prd_dic_sistema",
procedureName = "prd_dic_sistema",
parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "p_nro_evaluacion", type = Long.class),
#StoredProcedureParameter(mode = ParameterMode.OUT, name = "p_dictamen", type = String.class),
#StoredProcedureParameter(mode = ParameterMode.OUT, name = "p_respuesta", type = String.class)
}
)
}
)
public class DictaminationOperation implements Serializable {
attributes, constructor, getters and setters...
}
My error
Error calling CallableStatement.getMoreResults; SQL [prd_dic_sistema];
wrong number of types of arguments in call to 'PRD_DIC_SISTEMA'

Spring Data JPA : Stored Procedure with Schema Name

Please if anyone has experienced calling oracle stored procedure from spring data specifying schema, package and procedure name.
I have the following entity :
#Entity
#Table(name = "ENTITY", schema = "SCHEMA_ENTITY")
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(name = "name1",
procedureName = "packageName.procName",
parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "param1", type = String.class),
#StoredProcedureParameter(mode = ParameterMode.OUT, name = "return_value", type = BigDecimal.class)
})})
public class EntityExp {
#Id
private Long keyId;
...
}
Repository :
public interface EntityRepository extends JpaRepository<EntityExp, Long> {
#Procedure(name = "name1")
BigDecimal test(#Param("param1") String param1);
}
In the service implemetation, after autowiring it, I call the procedure like :
BigDecimal returnVal = entityRepository.test(param1);
The oracle stored proc definition is :
create or replace PACKAGE packageName as
function procName(param1 IN VARCHAR)
RETURN NUMBER;
END packageName;
create or replace PACKAGE BODY packageName
IS
function procName (param1 IN VARCHAR)
RETURN NUMBER
IS
BEGIN
return 1;
END;
END;
The procedure works fine if I call it using PL/Sql..
And I got the following error :
PLS-00201: identifier 'package.procName' must be declared
I also tested many configs, like specifying the schema in the procedure:
#Procedure(name = "SCHEMA_ENTITY.name1")
BigDecimal test(#Param("param1") String param1);
But still fails...
I can't find any example using schema + package + procedureName while calling the stored procedure...
Any suggestions ?
I'm not quite sure that understood your issue completely, but I'll try to share some information since I had a related issue recently.
The first item is related to the way you call the stored procedure. It looks like the returned type of the stored procedure is not currently supported by Spring-data. For more info link. However, with void it is working fine.
I resolved that by creating a separate Repository where I call the procedures which return result through the entityManager. An example which illustrates that link.
The second item is about schema name. I believe when you resolve the first item you could use this question to try to resolve it. In a nutshell, I set the schema name in the procedureName annotation attribute name.
#NamedStoredProcedureQuery(
name="procName",
procedureName="<schema_name>.proc_name"
)
#Entity
#Table
public class User {
...
}
Hope it helps.

How to insert into db in spring-data?

I want to make a request that inserts data into my database. The table has 4 columns: ID_DOCUMENT (PK), ID_TASK, DESCRIPTION, FILEPATH
Entity
...
#Column(name = "ID_TASK")
private Long idTask;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "FILEPATH")
private String filepath;
...
Repository
#Modifying
#Query("insert into TaskDocumentEntity c (c.idTask, c.description, c.filepath) values (:id,:description,:filepath)")
public void insertDocumentByTaskId(#Param("id") Long id,#Param("description") String description,#Param("filepath") String filepath);
Controller
#RequestMapping(value = "/services/tasks/addDocument", method = RequestMethod.POST)
#ResponseBody
public void set(#RequestParam("idTask") Long idTask,#RequestParam("description") String description,#RequestParam("filepath") String filepath){
//TaskDocumentEntity document = new TaskDocumentEntity();
taskDocumentRepository.insertDocumentByTaskId(idTask,descriere,filepath);
}
When I run my test, I get this error:
Caused by: org.hibernate.hql.ast.QuerySyntaxException: expecting OPEN, found 'c' near line 1, column 32 [insert into TaskDocumentEntity c (c.idTask, c.descriere, c.filepath) values (:id,:descriere,:filepath)]
I tried to remove the alias c, and still doesn`t work.
Spring data provides out of the box save method used for insertion to database - no need to use #Query. Take a look at core concepts of springData (http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.core-concepts)
thus in your controller just create object TaskDocumentEntity and pass it to repository
#RequestMapping(value = "/services/tasks/addDocument", method = RequestMethod.POST)
#ResponseBody
public void set(#RequestParam("idTask") Long idTask,#RequestParam("description") String description,#RequestParam("filepath") String filepath){
// assign parameters to taskDocumentEntity by constructor args or setters
TaskDocumentEntity document = new TaskDocumentEntity(idTask,descriere,filepath);
taskDocumentRepository.save(document);
}
There is a way to do this but it depends on the db you're using. Below worked for me in Oracle (using Dual table):
#Repository
public interface DualRepository extends JpaRepository<Dual,Long> {
#Modifying
#Query("insert into Person (id,name,age) select :id,:name,:age from Dual")
public int modifyingQueryInsertPerson(#Param("id")Long id, #Param("name")String name, #Param("age")Integer age);
}
So in your case, it would be (if Oracle):
#Modifying
#Query("insert into TaskDocumentEntity (idTask,description,filepath) select :idTask,:description,:filepath from Dual")
public void insertDocumentByTaskId(#Param("idTask") Long id,#Param("description") String description,#Param("filepath") String filepath)
I'm not sure which db you're using, here's a link which shows at the bottom which db's support select stmts without a from clause : http://modern-sql.com/use-case/select-without-from

Resources