There is an oracle stored procedure:
test_owner.pkg_xyz.daycalculation(p_parameter = >"Tuesday");
My Simple JDBCCall to call Oracle procedure:
public class StoredExecuter {
*fields*
public void ExecuteDailyProced (String dayId) {
try {
String slqPackage = "pkg_xyz";
String procName = "daycalculation";
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
.withSchemaName("test_owner")
.withCatalogName(sqlPackage)
.withProcedureName(procName)
.declaredParameters(new SqlParameter(dayId,OracleTypes.Varchar));
jdbcCall.setAccessCallParameterMetaData(false);
jdbcCall.execute();
}
catch(Exception e) {
throw new RunTimeException("Cannot perform procedure due to : " +e.getMessage(),e);
}
}
}
Exception:
java.lang.RuntimeException: Cannot perform procedure due to : 0
as tests.StoredExecuter.ExecuteDailyProced......
Caused by: java.lang.ArrayIndexOutOfBoundsException: 0
at org.springframework.jdbc.core.metadata.CallMetaDataContext.matchInParameterValuesWithCallParameters(CallMetaDataContext.java:577)
at org.springframework.jdbc.core.simple.AbstractJdbcCall.matchInParameterValuesWithCallParameters(AbstractJdbcCall.java:442)
at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:376)
at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:188)
Appreciate any help to resolve this problem!
Thank you
Related
I'm trying to call a stored procedure with JDBC to an Oracle database, but I have a couple of issues.
SQL package definition with stored procedure to call
create or replace PACKAGE PACK AS
TYPE type_rec IS RECORD (
module VARCHAR2(40),
value VARCHAR2(80),
message VARCHAR2(4000));
TYPE type_msg_array IS VARRAY(250) OF type_rec;
PROCEDURE FUNC (
provco IN VARCHAR2,
id IN VARCHAR2,
code OUT NUMBER,
msg OUT VARCHAR2,
msg_array IN OUT type_msg_array);
END PACK;
Main method that creates the request and calls the stored procedure
public Map<String, Object> executeFunc(final String db, final RequestPojo request) {
Map<String, Object> inParamMap = new LinkedHashMap<>();
Map<String, Object> funcOutput = null;
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(getJdbcTemplate(db).getJdbcTemplate().getDataSource());
MessagePojo message = new MessagePojo();
List<MessagePojo> messageList = new ArrayList<>();
messageList.add(message);
List<Object> objectList = new ArrayList<>(messageList);
try (final Connection connectionWrapper = jdbcCall.getJdbcTemplate().getDataSource().getConnection()){
buildFuncParameters(jdbcCall, inParamMap, request);
inParamMap.put("msg_array", new ScriptArray(objectList, connectionWrapper));
funcOutput = jdbcCall.execute(inParamMap);
} catch (SQLException sqlEx) {
throw new DataRetrievalFailureException(sqlEx.getMessage());
}
return funcOutput;
}
Helping method that builds the request
private void buildFuncParameters(SimpleJdbcCall jdbcCall, Map<String, Object> inParamMap, RequestPojo request) {
jdbcCall.withCatalogName("PACK");
jdbcCall.withProcedureName("FUNC");
jdbcCall.declareParameters(
new SqlParameter("provco", Types.VARCHAR),
new SqlParameter("id", Types.VARCHAR),
new SqlOutParameter("code", Types.NUMERIC),
new SqlOutParameter("msg", Types.VARCHAR),
new SqlInOutParameter("msg_array", java.sql.Types.ARRAY, "PACK".concat(".TYPE_MSG_ARRAY"))
);
jdbcCall.withoutProcedureColumnMetaDataAccess();
jdbcCall.setAccessCallParameterMetaData(false);
jdbcCall.withReturnValue();
inParamMap.put("provco", findCritSeqRequest.getProvco());
inParamMap.put("id", findCritSeqRequest.getId());
}
ScriptArray utility class
public class ScriptArray extends AbstractSqlTypeValue {
private List<Object> values;
private Connection oracleConnection;
public ScriptArray(List<Object> values, final Connection oracleConnection) {
this.values = values;
this.oracleConnection = oracleConnection;
}
#Override
protected Object createTypeValue(Connection con, int sqlType, String typeName)
throws SQLException {
return oracleConnection.unwrap(OracleConnection.class).createARRAY(typeName, values.toArray(new Object[values.size()]));
}
}
After the execution, I get the following error
ERROR org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{? = call PACK.FUNC(?, ?, ?, ?)}]; SQL state [99999]; error code [17074]; invalid name pattern: PACK.TYPE_MSG_ARRAY; nested exception is java.sql.SQLException: invalid name pattern: PACK.TYPE_MSG_ARRAY
Hope you can help me out on this one.
I have a code, that when an error returns from a procedure, I need to update a table column in oracle. However, at the time of the update (inside the catch block), the following error occurs:
org.springframework.dao.ConcurrencyFailureException: PreparedStatementCallback; SQL [UPDATE TB_XPTO SET COLUMN_XPTO = XX WHERE ID_XPTO = ?]; ORA-02091: transação repetida
; nested exception is java.sql.SQLTransactionRollbackException: ORA-02091:
My code:
try {
jdbcTemplate.update ("call PROCEDURE_XPTO(?)", ID_XPTO);
} catch (Exception e) {
jdbcTemplate.update("UPDATE TB_XPTO SET COLUMN_XPTO = XX WHERE ID_XPTO = ?", idXpto);
}
My data source Config class
#Bean
public DataSourceBuilder<?> dataSourceBuilder(Environment springEnvironment) {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("oracle.jdbc.OracleDriver");
dataSourceBuilder.url("jdbc:oracle:thin:#//server:1521/database.com.br");
dataSourceBuilder.username("user");
dataSourceBuilder.password("pass");
return dataSourceBuilder;
}
#Bean
public DataSource getDataSource(DataSourceBuilder<?> dataSourceBuilder) {
return dataSourceBuilder.build();
}
Any idea ?
thanks for your answer, but worked for me, using #Transactional, in the method that calls the procedure.
I have been trying to call a function that i created using jpa but i keep getting this error
(org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: 'udf_searchEmployeeLeaves' is not a recognized built-in function name.
Error Code: 195)
public List<EmployeeLeaves> searchEmployeeLeaves(String str) throws EmployeeLeavesException {
try {
Query query = em.createNativeQuery("SELECT udf_searchEmployeeLeaves(?1) FROM LAB ");
query.setParameter(1, str);
return query.getResultList();
} catch (Exception e) {
throw new EmployeeLeavesException("[searchEmployeeLeaves-ERROR]: " + e.getMessage());
}
}
I think the call is incorrect.
You have to call the table function like this:
Query query = em.createNativeQuery("SELECT * FROM udf_searchEmployeeLeaves(?1)");
I trying to use spring batch with storedProcedureItemReader
and always i get this exception
and i cant found the error i use Sybase at BBDD
org.springframework.batch.item.ItemStreamException: Failed to initialize the reader
Caused by: org.springframework.jdbc.BadSqlGrammarException: Executing stored procedure; bad SQL grammar [{call PROCEDURE(?)}]; nested exception is java.sql.SQLException: Invalid parameter index 0.
Caused by: java.sql.SQLException: Invalid parameter index 0.
this is java spring code
#Bean
protected ItemReader<AuditKpi> auditKpiRead(DataSource dataSource) throws Exception{
StoredProcedureItemReader<AuditKpi> storedProcedureItemReader = new StoredProcedureItemReader<AuditKpi>();
SqlParameter[] parameter = {new SqlParameter("#INDATE", Types.SQL_DATETIME)};
PreparedStatementSetter stament = new PreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setDate(1, new java.sql.Date(new Date().getTime()));
}
};
storedProcedureItemReader.setDataSource(dataSource);
storedProcedureItemReader.setProcedureName("PROCEDURE");
storedProcedureItemReader.setRowMapper(new BeanPropertyRowMapper<AuditKpi>(AuditKpi.class));
storedProcedureItemReader.setParameters(parameter);
storedProcedureItemReader.setPreparedStatementSetter(stament);
storedProcedureItemReader.afterPropertiesSet();
storedProcedureItemReader.setVerifyCursorPosition(false);
System.out.println(storedProcedureItemReader.getSql());
return storedProcedureItemReader;
}
And this is my SQL code
CREATE PROCEDURE PROCEDURE (IN #INDATE DATE)
AS
...
GO
Thranks for your help
I have a stored procedure defined in PostgresSql as below:
CREATE OR REPLACE FUNCTION update_points(accountId bigint, points numeric(19,5)) RETURNS void AS $$
...
...
$$ LANGUAGE plpgsql;
And I call the following method to call the procedure:
public void updatePoints(final Account account, final BigDecimal points) {
SimpleJdbcCall simpleCall = new SimpleJdbcCall(coreJdbcTemplate).withFunctionName("update_points");
SqlParameterSource inputs = new MapSqlParameterSource()
.addValue("accountId", account.getId())
.addValue("points", points);
simpleCall.execute(inputs);
}
When the method is called, I get following spring error:
org.springframework.dao.DataIntegrityViolationException: CallableStatementCallback; SQL [{? = call update_points()}]; No value specified for parameter 1.; nested exception is org.postgresql.util.PSQLException: No value specified for parameter 1.
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:102)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:1137)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:1173)
at org.springframework.jdbc.core.simple.AbstractJdbcCall.executeCallInternal(AbstractJdbcCall.java:388)
at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:348)
at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:190)
at net.exchangesolutions.veo.dao.AccountTransactionDaoImpl.updateRewardsConsumedAmount(AccountTransactionDaoImpl.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
I tried another way to call the procedure with CallableStatement in which case the function is not called at all.
Do you know what is the problem with the code or have you any suggestion about how to call the procedure from SpringJPA?
Thanks!
EDIT:
This is how I call with CallableStatement:
public void updatePoints(final Account account, final BigDecimal points) {
Connection connection;
try {
connection = coreJdbcTemplate.getDataSource().getConnection();
CallableStatement callableSt = connection.prepareCall("{call update_points(?, ?)}");
callableSt.setLong(1, account.getId());
callableSt.setBigDecimal(2, points);
callableSt.executeUpdate();
} catch (SQLException e) {
}
}
I resolved this problem by using following method. I could not figure out why the two approaches above did not work. Anyway, following solution is working now.
public void updatePoints(final Account account,
final BigDecimal points) {
coreJdbcTemplate.execute(new CallableStatementCreator() {
public CallableStatement createCallableStatement(Connection con)
throws SQLException {
CallableStatement cs = con
.prepareCall("{call update_points(?, ?)}");
cs.setLong(1, account.getId());
cs.setBigDecimal(2, points);
return cs;
}
}, new CallableStatementCallback() {
public Object doInCallableStatement(CallableStatement cs)
throws SQLException {
cs.execute();
return null;
}
});