Spring StoredProcedure Optional Parameters - java

I have a procedure in Oracle that has 12 total parameters and 3 optional. How can I account for these optional parameters if I'm using the StoredProcedure object in Spring 3.1.0?
Here's what I have so far in my StoredProcedure class
public Map<String, Object> execute(Evaluation evaluation) {
Map<String, Object> input_params = new HashMap<String, Object>();
input_params.put(COURSE_MAIN_PK1_INPUT_PARAM, evaluation.getCourseId());
input_params.put(USERS_PK1_INPUT_PARAM, evaluation.getUsersPk1());
input_params.put(ACCREDITATION_PK1_INPUT_PARAM, evaluation.getAccreditationPk1());
input_params.put(TYPE_PK1_INPUT_PARAM, evaluation.getTypePk1());
input_params.put(PRIVACY_TYPE_PK1_INPUT_PARAM, evaluation.getPrivacyTypePk1());
input_params.put(FORM_TYPE_PK1_INPUT_PARAM, evaluation.getFormTypePk1());
input_params.put(TITLE_INPUT_PARAM, evaluation.getTitle());
input_params.put(DESCRIPTION_INPUT_PARAM, evaluation.getDescription());
if(evaluation.getStartDate() != null) {
input_params.put(START_DATE_INPUT_PARAM, new java.sql.Date(evaluation.getStartDate().getMillis()));
}
if(evaluation.getEndDate() != null) {
input_params.put(END_DATE_INPUT_PARAM, new java.sql.Date(evaluation.getEndDate().getMillis()));
}
input_params.put(SAVE_TO_GRADECENTER_INPUT_PARAM, evaluation.getGradeCenterColumn());
input_params.put(CREATE_ANNOUNCEMENT_INPUT_PARAM, evaluation.getAnnouncement());
return super.execute(input_params);
}
The problem with this is that I'm supplying 12 parameters and if the start and end dates are null, now I'm supplying 10 and getting an exception.
The default values for the dates in the database is null.

JDBC's PreparedStatement provides a facility to set null values to parameters using the setNull method. So, as long as you pass all the parameters to the stored procedure if they are null, Spring would be able to prepare the statement and execute it.
So, you needed to add the input parameters whose values are null, to the Map that is sent to the stored procedure call.
input_params.put(START_DATE_INPUT_PARAM,
(null != evaluation.getStartDate()
? new java.sql.Date(evaluation.getStartDate().getMillis())
: null));
The same would apply to END_DATE_INPUT_PARAM as well.

Related

SimpleJdbcCall - How to extract table parameter from stored procedure in package

This is my situation: I am trying to call a procedure (which has been declared within a PL/SQL package) with two parameters:
PROCEDURE p_process_docs (
p_cod IN NUMBER,
p_doc_t OUT O_DOC_T
)
O_DOC_T is defined as following:
create or replace TYPE O_DOC_T FORCE AS TABLE OF O_DOC_S;
And O_DOC_S definition is like this:
create or replace TYPE O_DOC_S FORCE AS OBJECT
(
COD_DOC_TYPE VARCHAR2(3),
COD_DOCUMENT VARCHAR2(20),
...
,CONSTRUCTOR FUNCTION O_DOC_S(
P_DOC_TYPE VARCHAR2,
P_DOCUMENT VARCHAR2,
...
);
With SimpleJdbcCall I'm trying to read that second parameter, so I prepared this:
private List<O_Doc_S> processDocs(final String cod) {
List<O_Doc_S> result = null;
RowMapper<O_Doc_S> rm = new ParameterizedRowMapper<O_Doc_S>() {
#Override
public O_Doc_SmapRow(ResultSet rs, int rowNum) throws SQLException {
O_Doc_Sresult = new O_Doc_S();
result.setCod_doc_type(rs.getInt("cod_doc_type"));
result.setCod_document(rs.getString("cod_tipo_docum"));
// Rest of mappings
return result;
}
};
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(dataSource)
.withCatalogName(CATALOG_NAME)
.withProcedureName("p_process_docs ")
.useInParameterNames("p_cod")
.returningResultSet("p_doc_t", rm);;
Map<String, Object> inParamMap = new HashMap<String, Object>();
inParamMap.put("p_cod", Integer.valueOf(cod));
SqlParameterSource in = new MapSqlParameterSource(inParamMap);
try {
Map<String, Object> out = simpleJdbcCall.execute(in);
// Iterate and store in result
logger.info("Number of values received: ");
} catch (Exception e) {
logger.error("Error");
result = new ArrayList<O_Doc_S>();
}
return result;
}
But I got this error on the execute line:
java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'p_process_docs '
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
I have tried many changes (declare the in/out params, switch to a function, remove/add params) and everything ended up in error (being "wrong number or type of arguments" the most commmon). I'm quite sure it is possible to get a list of records from a PL/SQL procedure/function but it escapes me how to do it properly. All I have found were explanations on how to read a single basic value at best. What I require is much more complex.
Any suggestions? Also, the solution must fulfill these two conditions:
It is mandatory to return a list/table of values.
It must work with JDK 1.6.
The procedure can be modified (even switch it to a function) but the same doesn't apply to the types.

Using ElasticSearch's script_upsert to create a document

According to the official documentation Update API - Upserts one can use scripted_upsert in order to handle update (for existing document) or insert (for new document) form within the script. The thing is they never show how the script should look to do that. The Java - Update API Doesn't have any information on the ScriptUpsert uses.
This is the code I'm using:
//My function to build and use the upsert
public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
UpdateRequest request = new UpdateRequest(index, type, key);
request.scriptedUpsert(true);
request.script(script);
if (parent != null) {
request.parent(parent);
}
this.bulkProcessor.add(request);
}
//A test call to validate the function
String scriptSource = "if (!ctx._source.hasProperty(\"numbers\")) {ctx._source.numbers=[]}";
Map<String, List<Integer>> parameters = new HashMap<>();
List<Integer> numbers = new LinkedList<>();
numbers.add(100);
parameters.put("numbers", numbers);
bulk.scriptedUpsert("testUser", null, scriptSource, parameters);
And I'm getting the following exception when "testUser" documents doesn't exists:
DocumentMissingException[[user][testUser]: document missing
How can I make the scriptUpsert work from the Java code?
This is how a scripted_upsert command should look like (and its script):
POST /sessions/session/1/_update
{
"scripted_upsert": true,
"script": {
"inline": "if (ctx.op == \"create\") ctx._source.numbers = newNumbers; else ctx._source.numbers += updatedNumbers",
"params": {
"newNumbers": [1,2,3],
"updatedNumbers": [55]
}
},
"upsert": {}
}
If you call the above command and the index doesn't exist, it will create it, together with the newNumbers values in the new documents. If you call again the exact same command the numbers values will become 1,2,3,55.
And in your case you are missing "upsert": {} part.
As Andrei suggested I was missing the upsert part, changing the function to:
public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
UpdateRequest request = new UpdateRequest(index, type, key);
request.scriptedUpsert(true);
request.script(script);
request.upsert("{}"); // <--- The change
if (parent != null) {
request.parent(parent);
}
this.bulkProcessor.add(request);
}
Fix it.

How to restrict the field in Mongodb

I have to restrict some field which are there in processtemplate class. Below is the method which i have developed. When i pass some id it gives me runtime exception. Please help me out
public ProcessTemplate get(String id) throws GRIDRecordsDataManagerException {
ProcessTemplate entity = null;
try {
BasicDBObject qry = new BasicDBObject();
Map<String, Object> whereMap = new HashMap<String, Object>();
whereMap.put("id", id);
qry.putAll(whereMap);
BasicDBObject field = new BasicDBObject();
field.put("name", 1);
field.put("status", 1);
field.put("description", 1);
DBCursor results = dbCollection.find(qry, field);
if (results != null && results.hasNext()) {
DBObject dbObj = results.next();
entity = new ProcessTemplate();
entity.setId((String) dbObj.get("id"));
entity.setProcessName((String) dbObj.get("name"));
entity.setStatus((String) dbObj.get("status"));
entity.setDescription((String) dbObj.get("description"));
System.out.println(entity);
}
} catch (Exception e) {
}
return entity;
}
Answer copied from jira.mongodb.org
When querying a GridFS collection on specific fields, it works when no
GridFS file was ever stored on that collection. Once a file was saved
to the collection, the query on specific fields fails with "can't load
partial GridFSFile file".
...
For now I'll reset the object associated with the collection, quite a
hack though: if (Objects.equal(GridFSDBFile.class,
coll.getObjectClass())) { coll.setObjectClass(null); }
...
Hi, A collection can have an associated ObjectClass and this
information is cached, allowing it to be set once and then reused
elsewhere in your code. Once it is set you have to explicitly unset
it. GridFS is a specification for storing and retrieving files that is
built upon the driver. GridFS is opinionated about how it is to be
used, as such it sets the ObjectClass for the files collection when
you create a GridFS instance. The reason it throws an error is the
GridFSFile is not expected to be used in the way you've show as it
could represent a partial part of a file and which is why it throws
the "can't load partial GridFSFile file" runtime error. As you've
found out the associated ObjectClass can only unset by resetting the
ObjectClass back to null.
In your case it is translated to:
BasicDBObject qry = new BasicDBObject("id",id); //You can save 3 lines of code here, btw
BasicDBObject field = new BasicDBObject();
...
if (Objects.equal(GridFSDBFile.class, dbCollection.getObjectClass()))
dbCollection.setObjectClass(null);
DBCursor results = dbCollection.find(qry, field);
...

Ibatis out params from stored procedure in Oracle 11g

I have a stored procedure which has three out params all user defined types.
I use ibatis as ORM from java code to call the stored procedure.
How do i configure this stored procedure call in ibatis xml
and how do I get the results back in my java code.
procedure test(
p_a in int default 0 ,
p_b in number default 0,
p_criteria out TBL_A,
p_baseline out TBL_B,
p_results out TBL_C);
Any help would be highly appreciated.
thanks,
gagan suri
In your xml configuration provide parameters with in/out mode (jdbcType is optional):
<procedure id="callProcedure1" parameterClass="map">
{
call procedure1(
#value1,jdbcType=DECIMAL,mode=INOUT#,
#value2,jdbcType=DECIMAL,mode=INOUT#,
#value3,jdbcType=DECIMAL,mode=INOUT#,
)
}
</procedure>
And in your dao class just get your results from parameters:
final Map<String, Object> params = new HashMap<String, Object>();
//provide input parameters here
params.put("value1", 1);
AbstractSQLMapDao.queryForObject("namespace.callProcedure1", params);
//retrieve you output
Double value1 = params.get("value1")

Stored Procedure returning multiple tables to spring jdbc template

Iam calling a stored procedure from my Spring DAO class using JdbcTemplate. My problem is that, stored procedure returns multiple tables. Is there a way to access multiple tables using Spring JdbcTemplate.
If I use
jdbcTemplate.queryForList(myStoredProc, new Object[]{parameters}
iam getting only first table from the result.
My database is SQL Server 2005.
Is there any method other than jdbcTemplate for my requirement?
The solution sinha referenced didn't work for me. I was able to solve this using JdbcTemplate#call(CallableStatementCreator, List<SqlParameter>). For example:
private static final String sql = "{call schema_name.the_stored_procedure(?, ?, ?)}";
// The input parameters of the stored procedure
private static final List<SqlParameter> declaredParams = Arrays.asList(
new SqlParameter("nameOfFirstInputParam", Types.VARCHAR),
new SqlParameter("nameOfSecondInputParam", Types.VARCHAR),
new SqlParameter("nameOfThirdInputParam", Types.VARCHAR));
private static final CallableStatementCreatorFactory cscFactory
= new CallableStatementCreatorFactory(sql, declaredParams);
// The result sets of the stored procedure
private static final List<SqlParameter> returnedParams = Arrays.<SqlParameter>asList(
new SqlReturnResultSet("nameOfFirstResultSet", SomeRowMapper.INSTANCE),
new SqlReturnResultSet("nameOfSecondResultSet", SomeOtherRowMapper.INSTANCE));
public static Map<String, Object> call(JdbcTemplate jdbcTemplate,
String param0,
String param1,
String param2) {
final Map<String, Object> actualParams = new HashMap<>();
actualParams.put("nameOfFirstInputParam", param0);
actualParams.put("nameOfSecondInputParam", param1);
actualParams.put("nameOfThirdInputParam", param2);
CallableStatementCreator csc = cscFactory.newCallableStatementCreator(actualParams);
Map<String, Object> results = jdbcTemplate.call(csc, returnedParams);
// The returned map will including a mapping for each result set.
//
// {
// "nameOfFirstResultSet" -> List<SomeObject>
// "nameOfSecondResultSet" -> List<SomeOtherObject>
// }
//
// For this example, we just return the heterogeneous map. In practice,
// it's better to return an object with more type information. In other
// words, don't make client code cast the result set lists. Encapsulate
// that casting within this method.
return results;
}
See http://static.springsource.org/spring/docs/2.0.7/reference/jdbc.html#jdbc-StoredProcedure
The example given in this section is exactly for your case where the stored procedure returns multiple result-sets. Although the example given there is for Oracle, but it should work in the same way for MS SQL Server also.

Categories