SimpleJdbcCall always omits the first parameter in function calls - java

I'm trying to use the SimpleJdbcCall class to call functions in an Oracle package, but every call ignores the first input parameter.
My code looks like this:
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate())
.withSchemaName("MY_SCHEMA")
.withCatalogName("MY_PACKAGE")
.withFunctionName("MY_FUNCTION")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlParameter("FIRST_ARGUMENT", Types.VARCHAR), new SqlParameter("SECOND_ARGUMENT", Types.VARCHAR));
SqlParameterSource params = new MapSqlParameterSource().addValue("FIRST_ARGUMENT", "VALUE1").addValue("SECOND_ARGUMENT", "VALUE2");
Integer result = call.executeFunction(Integer.class, params);
with my function being:
FUNCTION MY_FUNCTION(FIRST_ARGUMENTvarchar2, SECOND_ARGUMENTvarchar2) RETURN number;
The stacktrace shows this kind of errors:
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{? = call MY_SCHEMA.MY_PACKAGE.MY_FUNCTION(?)}];
A parameter has been removed. A call to another function with just one parameter throws a similar error:
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{? = call MY_SCHEMA.MY_PACKAGE.MY_OTHER_FUNCTION()}];
I've tried debugging the Spring code, spring-boot-starter-jdbc:2.0.1.RELEASE (2.0.0 too), and I've come accross this code in the org.springframework.jdbc.core.metadata.CallMetaDataContext class, when composing the call:
if (isFunction() || isReturnValueRequired()) {
callString = "{? = call " +
(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "") +
(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "") +
procedureNameToUse + "(";
parameterCount = -1;
}
else {
callString = "{call " +
(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "") +
(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "") +
procedureNameToUse + "(";
}
for (SqlParameter parameter : this.callParameters) {
if (!(parameter.isResultsParameter())) {
if (parameterCount > 0) {
callString += ", ";
}
if (parameterCount >= 0) {
callString += createParameterBinding(parameter);
}
parameterCount++;
}
}
callString += ")}";
If I've understood the code, the first parameter will always be ommited, am I right?
Has anybody had success in this situation?
M. Deinum is right and the return parameter must be specified too, I expected Spring to automatically add it when working with functions.
My code now:
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate())
.withSchemaName("MY_SCHEMA")
.withCatalogName("MY_PACKAGE")
.withFunctionName("MY_FUNCTION")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlOutParameter("return",Types.INTEGER)
,new SqlParameter("FIRST_ARGUMENT", Types.VARCHAR)
,new SqlParameter("SECOND_ARGUMENT", Types.VARCHAR));
SqlParameterSource params = new MapSqlParameterSource().addValue("FIRST_ARGUMENT", "VALUE1").addValue("SECOND_ARGUMENT", "VALUE2");
Integer result = call.executeFunction(Integer.class, params);

Related

Transactions from ArangoDB java driver fails to change anything in the database

I am trying to send a transaction through the Java driver in my spring application.
The following is the simplified code.
#Test
public void rawTransactionTest(){
var appContext = new AnnotationConfigApplicationContext(DataLoaderApplication.class);
var arangoOperations = appContext.getBean(ArangoOperations.class);
String action = "function(){\n" +
" db = require(\"#arangodb\").db; \n" +
"db._query(\"LET doc = {title: \\\"Hello\\\"} "+
"UPSERT { _key: doc._key } INSERT doc._key == null ? UNSET(doc, \\\"_key\\\") : doc " +
"REPLACE doc IN Books OPTIONS { ignoreRevs: false } RETURN NEW\");\n" +
"return \"Success\"; \n" +
"}";
System.out.println(action);
var tOpts = new TransactionOptions();
tOpts.writeCollections("Books");
tOpts.waitForSync(true);
var result = arangoOperations.driver().db().transaction(action, String.class, tOpts);
System.out.println("Commit");
}
This returns the return value "Success" in the variable result. But the database remains unchanged. Doing the same thing in ArangoShell works perfectly fine. The ArangoShell code is as follows -
db._executeTransaction({
collections: {
write: ["Books"]
},
action: function(){
db = require("#arangodb").db;
db._query("LET doc = {title: \"Hello\"} UPSERT { _key: doc._key } "+
"INSERT doc._key == null ? UNSET(doc, \"_key\") : doc REPLACE doc"+
" IN Books OPTIONS { ignoreRevs: false } RETURN NEW");
return "Success";
}
});
This code works fine from the shell. Other non-transaction queries work fine from he same Spring-container.
What might be the problem?
The .db() only points to the _system database. Had to pass the database name to fix it.

JUnit testing (positive and negative testing)

This is the code I have written for JUnit Testing for positive and negative testing.
#Test
public void getMaintenenceIntervalsByMetadataOKTest() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.set("vinModelYear", "2016");
params.set("vinModelCode", "1633F6");
params.set("vinEngineCode", "CZTA");
params.set("interval", "100000");
params.set("vinTransmissionCode", "");
params.set("importerNumber", "");
params.set("makeCode", "V");
params.set("descriptionText", "");
params.set("languageCode", "en-US");
params.set("dealerCode", "408083");
mvc.perform(get("/upg-admin-controller/maintenence-intervals-by-metadata")
.contentType(MediaType.APPLICATION_JSON)
.params(params))
.andExpect(status().isAccepted());
}
#Test
public void getMaintenenceIntervalsByMetadata400Test()
throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.set("vinModelYear", "2000");
params.set("vinModelCode", "8727R9");
params.set("vinEngineCode", "GTAV");
params.set("interval", "100000");
params.set("vinTransmissionCode", "");
params.set("importerNumber", "");
params.set("makeCode", "T");
params.set("descriptionText", "");
params.set("languageCode", "sp-MX");
params.set("dealerCode", "120021");
mvc.perform(get("/upg-admin-controller/maintenence-intervals-by-metadata")
.contentType(MediaType.APPLICATION_JSON)
.params(params))
.andExpect(status().isBadRequest());
}
Error:
Error: java.lang.AssertionError: Status expected:<202> but was:<400>.
I have been trying to fix it but cannot find a solution. Using EclEmma extension on Eclipse. (sorry if the code is out of line. The text box is small it splits one line of code into two lines.)
Also this is the Controller code that I am working with that has the QueryParams.
#RequestMapping(value = "/maintenence-intervals-by-metadata", method = RequestMethod.GET)
public ResponseEntity<List<AdminMaintenanceIntervalReponse>> findMaintenenceIntervalsByMetadata( #QueryParam("modelYear") String modelYear,
#QueryParam("modelCode") String modelCode, #QueryParam("engineCode") String engineCode, #QueryParam("interval") String interval ,
#QueryParam("transmissionCode") String transmissionCode , #QueryParam("importer") String importer, #QueryParam("make") String make,
#QueryParam("descriptionText") String descriptionText, #QueryParam("languageCode") String languageCode, #QueryParam("dealerCode") String dealerCode, #QueryParam("brand") String Brand) throws MPMSException {
LOGGER.log(Level.INFO, "Entered UPGAdminServiceController, getAllMaintenenceIntervalsByMetadata");
LOGGER.log(Level.INFO, "modelYear =" + modelYear +" modelCode = " + modelCode +" engineCode = " + engineCode +" interval = " + interval + "transmissionCode = " + transmissionCode + "importer = " + importer + "make = " + make + "descriptionText = " + descriptionText);
List<AdminMaintenanceIntervalReponse> allMaintenanceIntervalsList = new ArrayList<AdminMaintenanceIntervalReponse>();
try{
Integer modelYearParam = null;
if (modelYear!=null){
modelYearParam = Integer.parseInt(modelYear);
}
Integer intervalParam = null;
if (interval!=null){
intervalParam = Integer.parseInt(interval);
}
String modelCodeParam = null;
if (modelCode!=null){
modelCodeParam = String.valueOf(modelCode);
}
String engineCodeParam = null;
if (engineCode!=null){
engineCodeParam = String.valueOf(engineCode);
}
String transmissionCodeParam = null;
if (transmissionCode!=null){
transmissionCodeParam = String.valueOf(transmissionCode);
}
Integer importerParam = null;
if (importer!=null){
importerParam = Integer.parseInt(importer);
}
String makeParam = null;
if (make!=null){
makeParam = String.valueOf(make);
}
if (descriptionText!=null){
String.valueOf(descriptionText);
}
allMaintenanceIntervalsList = upgAdminMaintenanceCalcService.findMaintenanceIntervalsByMetadata(modelYearParam, modelCodeParam, engineCodeParam, intervalParam, transmissionCodeParam, importerParam, makeParam, descriptionText, languageCode, dealerCode);
} catch(MPMSException e){
throw e;
} catch (Exception e) {
throw new MPMSException(ErrorConstants.UNKNOWN.getErrorCode(), "No Data Available", ErrorConstants.UNKNOWN.toString(), e);
}
return new ResponseEntity<List<AdminMaintenanceIntervalReponse>>(allMaintenanceIntervalsList, HttpStatus.OK);
}
Can someone please help me correct this issue.
Your /maintenence-intervals-by-metadata endpoint has the following query parameters:
#QueryParam("modelYear")
#QueryParam("modelCode")
#QueryParam("engineCode")
#QueryParam("interval")
#QueryParam("transmissionCode")
#QueryParam("importer")
#QueryParam("make")
#QueryParam("descriptionText")
#QueryParam("languageCode")
#QueryParam("dealerCode")
#QueryParam("brand")
But your test is submitting a [GET] request to /maintenence-intervals-by-metadata with the following named parameters:
params.set("vinModelYear", "2016");
params.set("vinModelCode", "1633F6");
params.set("vinEngineCode", "CZTA");
params.set("interval", "100000");
params.set("vinTransmissionCode", "");
params.set("importerNumber", "");
params.set("makeCode", "V");
params.set("descriptionText", "");
params.set("languageCode", "en-US");
params.set("dealerCode", "408083");
So, the query params you supply do not match the query params expected by the /maintenence-intervals-by-metadata endpoint. There are name mismatches:
modelYear vs. vinModelYear
modelCode vs. vinModelCode
... etc
And at least one query parameter is not supplied: the endpoint declares #QueryParam("brand") but you are not supplying a parameter named "brand".
I suspect the message associated with the 400 error might include something like: Required String parameter '...' is not present.
If you change your invocation such that every one of the query parameters defined by the /maintenence-intervals-by-metadata endpoint has a supplied parameter value of the correct type (a String) then I think the 400 will no longer occur.

Getting a null-point exception in Neo4j data retrieval

I have the following code.
GraphDatabaseFactory dbFactory = new GraphDatabaseFactory();
GraphDatabaseService db= dbFactory.newEmbeddedDatabase("C:/Users/shadid/Documents/Neo4j/DB");
ExecutionEngine execEngine = new ExecutionEngine(db, null);
ExecutionResult execResult = execEngine.execute("MATCH (mat:TheMatrix) RETURN mat");
String results = execResult.dumpToString();
System.out.println(results);
I am getting a null point exception. I have tried running the command in the neo4j command line. So the data do exist. I am not quite sure where is the error. Quite a noob in neo4j so could someone please help me out
Here's the error I am getting by the way
Exception in thread "main" java.lang.NullPointerException
at org.neo4j.cypher.internal.CypherCompiler.(CypherCompiler.scala:69)
at org.neo4j.cypher.ExecutionEngine.createCompiler(ExecutionEngine.scala:237)
at org.neo4j.cypher.ExecutionEngine.(ExecutionEngine.scala:64)
at App.Main.main(Main.java:53)
Just found a more intuitive way of doing the same thing and it works yay!!!
try ( Transaction ignored = db.beginTx();
Result result = db.execute( "MATCH (n:TheIronGiant) RETURN n.`title: `" ) )
{
String rows ="";
while ( result.hasNext() )
{
Map<String,Object> row = result.next();
for ( Entry<String,Object> column : row.entrySet() )
{
rows += column.getKey() + ": " + column.getValue() + "; ";
}
rows += "\n";
}
System.out.println(rows);
}
You are using the ExecutionEngine constructor that takes a LogProvider as the second parameter, but passing a null value for it. If you called the single-parameter constructor instead, which does not take a LogProvider, you may not get the exception.
Also, ExecutionEngine class is now deprecated, and you should use GraphDatabaseService.execute() instead.

Multithreading issues for database insertion

I have a piece of JAVA code that is accessed by multiple threads.
synchronized (this.getClass())
{
System.out.println("stsrt");
certRequest.setRequestNbr(
generateRequestNumber(
certInsuranceRequestAddRq.getAccountInfo().getAccountNumberId()));
System.out.println("outside funcvtion"+certRequest.getRequestNbr());
reqId = Utils.getUniqueId();
certRequest.setRequestId(reqId);
System.out.println(reqId);
ItemIdInfo itemIdInfo = new ItemIdInfo();
itemIdInfo.setInsurerId(certRequest.getRequestId());
certRequest.setItemIdInfo(itemIdInfo);
dao.insert(certRequest);
addAccountRel();
System.out.println("end");
}
the function generateRequestNumber() generates a request number based on the data fetched from two database tables.
public String generateRequestNumber(String accNumber) throws Exception
{
String requestNumber = null;
if (accNumber != null)
{
String SQL_QUERY = "select CERTREQUEST.requestNbr from CertRequest as CERTREQUEST, "
+ "CertActObjRel as certActObjRel where certActObjRel.certificateObjkeyId=CERTREQUEST.requestId "
+ " and certActObjRel.certObjTypeCd=:certObjTypeCd "
+ " and certActObjRel.certAccountId=:accNumber ";
String[] parameterNames = { "certObjTypeCd", "accNumber" };
Object[] parameterVaues = new Object[]
{
Constants.REQUEST_RELATION_CODE, accNumber
};
List<?> resultSet = dao.executeNamedQuery(SQL_QUERY,
parameterNames, parameterVaues);
// List<?> resultSet = dao.retrieveTableData(SQL_QUERY);
if (resultSet != null && resultSet.size() > 0) {
requestNumber = (String) resultSet.get(0);
}
int maxRequestNumber = -1;
if (requestNumber != null && requestNumber.length() > 0) {
maxRequestNumber = maxValue(resultSet.toArray());
requestNumber = Integer.toString(maxRequestNumber + 1);
} else {
requestNumber = Integer.toString(1);
}
System.out.println("inside function request number"+requestNumber);
return requestNumber;
}
return null;
}
The tables CertRequest and CertActObjRel used in generateRequestNumber() are updated by the functions "dao.insert(certRequest);" and "addAccountRel();" used in my initial code respectively. Also the System.out.println() statements used in my initial code have following output.
stsrt
inside function request number73
outside funcvtion73
A1664886-5F84-45A9-AB5F-C69768B83EAD
end
stsrt
inside function request number73
outside funcvtion73
44DAD872-6A1D-4524-8A32-15741FAC0CA9
end
If you notice both the threads run in a synchronized manner, but when the request number is generated , it's the same. My assumption is the database updation for CertRequest and CertActObjRel is done when both the threads finish their execution.
Could anyone help me to fix this?

How to read Query Parameters key and value

javax.persistence.Query
Query query = ....
query.setParameter("PARAM_1","1")
.setParameter("PARAM_2","2")
.setParameter("PARAM_3","3")
...
...;
I want to get parameters and write Console. Like this;
System out ;
PARAM_1 - 1
PARAM_2 - 2
PARAM_3 - 3
...
...
java.util.Set<Parameter<?>> params = query.getParameters();
for (Parameter p : params) {
String paramName = p.getName();
System.out.print(paramName + " - ");
System.out.println(query.getParameterValue(paramName));
}
You just had to look at the javadoc, the method getParameters()
Query q = ...;
...
Set<Parameter<?>> parameters = q.getParameters();
for (Parameter<?> param : parameters){
if (null == param.getName()){
System.out.print(param.getPosition());
} else {
System.out.print(param.getName());
}
System.out.println(" - ");
System.out.println(q.getParameterValue(param));
}
You can try this:
Query query = ...;
String[] keys = new String[] {"PARAM_1", "PARAM_2", "PARAM_3"};
for(String key : keys) {
System.out.println(key + " - " + query.getParamValue(key));
}
check query interface. It has many methods like getParameter*(). See which one suits you.
getParameter() helps you to understand more. Please click here for more information.
This worked for me:
((NativeQueryImpl) fQuery).getNamedParameterMap()

Categories