sql error : Invalid conversion requested using Spring JdbcTemplate prepared statement - spring

I am getting the following "Invalid conversion requested" error when tried to insert a row in RECORDERS (oracle 11g) table using spring 3.0.5 JdbcTemplate API.
Any help is much appreciated.
Error
2013-12-03 19:14:40,125,ERROR,,,http-bio-8080-exec-3,RecorderController,Caught exception: org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [INSERT INTO RECORDERS(RECORDER_ID,RECORDER_NAME,RECORDER_TYPE,RECORDER_IP,RECORDER_URL,ACTIVE_IND)VALUES(?,?,?,?,?,?)]; SQL state [99999]; error code [17132]; Invalid conversion requested; nested exception is java.sql.SQLException: Invalid conversion requested
Here is our RECORDERS table structure
Column Length Type Nullable Primary Key
RECORDER_ID 3 NUMBER N 1
RECORDER_NAME 20 VARCHAR2 N
RECORDER_TYPE 1 CHAR(1) N
RECORDER_IP 20 VARCHAR2 N
RECORDER_URL 100 VARCHAR2 N
ACTIVE_IND 1 CHAR(1) N
DAO code:
public class RecorderDAOImpl {
#Autowired
private JdbcTemplate jdbcTemplate;
private static String INSERT_SQL="INSERT INTO RSDVR_RECORDERS"
+ "(RECORDER_ID,RECORDER_NAME,RECORDER_TYPE,RECORDER_IP,RECORDER_URL,"
+ "ACTIVE_IND)VALUES(?,?,?,?,?,?)";
public void register(Recorder recorder) throws DataAccessException{
int nextRowNum = this.getNextRowNum();
char activeInd =this.getActiveIndicator(recorder.getState());
Object[] objArr = new Object[] {nextRowNum,recorder.getName(),recorder.getType().charAt(0),
recorder.getIP(),recorder.getURL(),activeInd};
int[] objTypes = new int[]{Types.INTEGER,Types.VARCHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.CHAR};
this.jdbcTemplate.update(INSERT_SQL, objArr,objTypes);
}
private char getActiveIndicator(final String state){
LOGGER.info("Enter " + this.getClass().getName() + ".getActiveIndicator()");
return ("Online".equalsIgnoreCase(state)) ? 'Y': 'N';
}
private int getNextRowNum() throws DataAccessException{
//return next row number
}
}

Related

How to use JPA or JDBC to call specific PL/SQL function using REF CURSOR

My problem is that I want to call PL/SQL function in #PostConstruct method in Spring Boot.
This function returns information about tables in a database as you can see above:
CREATE OR REPLACE FUNCTION dbINFO
return sys_refcursor AS
table_info sys_refcursor;
begin
open table_info
for select table_name from all_tables where owner = 'HOMEUSER';
return table_info;
end;
I tried to use #NamedStoreProcedureQuery annotation but I don't have entity to use it with.
So I decided to try doing it with JDBC and so far I've got something like this.
private EntityManager entityManager;
public HospitalApplication(EntityManager entityManager) {
this.entityManager = entityManager;
}
#PostConstruct
private void init() throws SQLException {
System.out.println("\n\n\n\n\n\n");
EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
Connection connection = info.getDataSource().getConnection();
CallableStatement stmt = connection.prepareCall("BEGIN dbINFO(); END;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = ((OracleCallableStatement)stmt).getCursor(1);
while (rs.next()){
System.out.println(rs.getString(1));
}
rs.close();
stmt.close();
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
}
Problem is, my program is throwing java.sqlException about column has incorrect index.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hospitalApplication': Invocation of init method failed; nested exception is java.sql.SQLException: Incorrect column index
***EDIT****
I tried something like that and I am receiving error:
PLS-00905: obiekt HOMEUSER.DBINFO is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
#PostConstruct
private void init() throws SQLException {
System.out.println("\n\n\n\n\n\n");
EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
Connection connection = Objects.requireNonNull(info.getDataSource()).getConnection();
CallableStatement stmt = connection.prepareCall("{ ? = call dbINFO()}");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = (ResultSet) stmt.getObject(1);
while (rs.next()){
System.out.println(rs.getCursorName());
}
rs.close();
stmt.close();
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
}

Insert byte[] into blob field with spring's jdbcTemplate and stored procedure

I'm try to insert byte[] into blob field with stored procedure, and get an Exception :
Request processing failed; nested exception is org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT ID FROM sp_NEWFILE(?,?,?)]; nested exception is org.firebirdsql.jdbc.field.TypeConversionException: Error converting to object.
Model:
public class fileBody {
private int ID;
private byte[] BODY;
private String FILENAME; //getters an setters}
Insert it to database
public class FileBodyDaoImpl implements FileBodyDao {
public int insertData(final FileBody fileBody) throws IOException {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
LobHandler lobHandler = new DefaultLobHandler();
final InputStream in = new ByteArrayInputStream(fileBody.getBODY());
final int fileSize = in.available();
Map<String, Object> out = jdbcTemplate.queryForMap("SELECT ID FROM sp_NEWFILE(?,?,?)",
new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException,
DataAccessException {
ps.setString(1, fileBody.getFILENAME());
lobCreator.setBlobAsBinaryStream(ps, 2, in, fileSize);
ps.setNull(3, java.sql.Types.INTEGER);
}
});
int last_inserted = Integer.parseInt(String.valueOf(out.get("ID")));
return last_inserted;
}
And my stored procedure
create or alter procedure sp_NEWFILE (
FILENAME varchar(255),
BODY blob sub_type 0 segment size 80,
USEID integer)
returns (
ID integer)
as
begin
if (useid is not null) then ID=USEID;
else ID=GEN_ID(gen_filebody_id,1);
if ((FILENAME is NULL) or (FILENAME='')) then FILENAME='UNDEFINED';
INSERT INTO t_filebody(ID,BODY,FILENAME) VALUES(:ID,:BODY,:FILENAME);
suspend;
end^
and i get an Exception:
Request processing failed; nested exception is org.springframework.jdbc.BadSqlGrammarException:
PreparedStatementCallback;
bad SQL grammar [SELECT ID FROM sp_NEWFILE(?,?,?)]; nested exception is org.firebirdsql.jdbc.field.TypeConversionException: Error converting to object.
Versions:
jaybird-jdk17-2.2.5;
Source: firebird2.5 Version: 2.5.1.26351.ds4-2ubuntu0.1;
The problem is that queryForMap does not support a PreparedStatementCallback (contrary to for example execute), instead your anonymous object is considered a normal parameter for the query to execute, and Jaybird does not support this object type. And if Jaybird had supported it, you would have received an error for missing parameters 2 and 3.
Your code can be greatly simplified by passing the byte array:
Map<String, Object> out = jdbcTemplate.queryForMap("SELECT ID FROM sp_NEWFILE(?,?,?)",
fileBody.getFILENAME(), fileBody.getBODY(), null);
This works as Jaybird considers a BLOB SUB_TYPE 0 as a java.sql.Types.LONGVARBINARY and JDBC 4.2 appendix B declares that byte[] is the default type for that (although you can also use it as a java.sql.Types.BLOB).
As a side note, your stored procedure does not need to be selectable (removing SUSPEND makes it executable), and the procedure could also be replaced by using a TRIGGER to generate the primary key and retrieving the value either by using INSERT .. RETURNING .. or through the JDBC generated keys facility (which in turn is implemented in Jaybird through INSERT .. RETURNING ..).
For those seeking non-Jaybird solution to insert BLOB using spring jdbctemplate, the following syntax worked for me to use stored procedures which is different compared to insert via queries.
Insert via Queries
ByteArrayInputStream inputStream = new ByteArrayInputStream(file.getBytes());
ps.setBlob(1, inputStream);
Insert via Stored Procedure Call
Map<String, Object> inParams = new HashMap<>();
inParams.put("pi_some_id", id);
inParams.put("pi_file_blob", new SqlLobValue(file.getBytes()));
SqlParameterSource sqlParameterSource = new MapSqlParameterSource(inParams);
SqlParameter[] sqlParameters = {
new SqlParameter("pi_some_id", Types.VARCHAR),
new SqlParameter("pi_file_blob", Types.BLOB),
new SqlOutParameter("po_error_flag", Types.VARCHAR),
new SqlOutParameter("po_message", Types.VARCHAR)};
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate).withoutProcedureColumnMetaDataAccess().
withProcedureName(storedProcName).withCatalogName(packageName).
declareParameters(sqlParameters);
Map<String, Object> storedProcResult = simpleJdbcCall.execute(sqlParameterSource);

Spring JdbcTemplate and oracle arrayofnumber

I'm using Spring and Oracle database in my solution and i need to execute script
select count(1) from ELEMENTS, table(cast(? as arrayofnumbers)) session_ids
where root_session_id in session_ids.VALUE
but i have a problem with passing input parameter.
i try to pass List or array of BigInteger into
JdbcTemplate.queryForObject("select count(1) from ELEMENTS, table(cast(? as arrayofnumbers)) session_ids
where root_session_id in session_ids.VALUE", Integer.class, INPUT_PARAMS)
but has an Exception:
java.sql.SQLException: Invalid column type
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8861)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8338)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9116)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:9093)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:234)
at weblogic.jdbc.wrapper.PreparedStatement.setObject(PreparedStatement.java:357)
Does anyone have the same problem?
EDIT:
Forget to describe arrayofnumber. It's custom type:
TYPE arrayofnumbers as table of number(20)
Found the solution:
final BigInteger[] ids = new BigInteger[]{BigInteger.valueOf(9137797712513092132L)};
int count = jdbc.query("select count(1) from NC_DATAFLOW_ELEMENTS\n" +
" where root_session_id in (select /*+ cardinality(t 10) */ * from table(cast (? as arrayofnumbers)) t)"
, new PreparedStatementSetter() {
public void setValues(PreparedStatement preparedStatement) throws SQLException {
Connection conn = preparedStatement.getConnection();
OracleConnection oraConn = conn.unwrap(OracleConnection.class);
oracle.sql.ARRAY widgets = oraConn.createARRAY("ARRAYOFNUMBERS", ids);
preparedStatement.setArray(1, widgets);
}
}, new ResultSetExtractor<Integer>() {
public Integer extractData(ResultSet resultSet) throws SQLException, DataAccessException {
resultSet.next();
return resultSet.getInt(1);
}
});
out.println(count);
should note that type of array (ARRAYOFNUMBER) should be in upper case

like clause in spring jdbc

#Override
public List<String> getusers(String role) {
// TODO Auto-generated method stub
String namecount = "SELECT userName FROM users WHERE userName LIKE ?";
role="\"%" + role + "%\"";
List<String> names = jdbcTemplate.query("SELECT userName FROM users where userName like ?", new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString(1);
}
},role);
System.out.println(names);
return names;
}
I am not understanding why I am get this error , please can one say where it went wrong
Error message:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT userName FROM users userName like ?]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'like '%blabla%'' at line 1
You forget the WHERE keyword in the JdbcTemplate query.

Postgres Parameter Query for SimpleJdbcTemplate

I am trying to execute a parameter query for a Postgre database using Springs SimpleJdbcTemplate. My class that calls the query looks like this:
public class GeoCodeServiceImpl extends SimpleJdbcDaoSupport implements GeoCodeServiceInterface {
public static final String SELECT_STATEMENT = "SELECT ste_code, ste_code_type, name, fips_code " +
"FROM \"steGeo\" " +
"WHERE st_contains( the_geom, ST_GeomFromText('POINT(:lon :lat)',4269))";
public List<GeoCode> getGeoResults(Double lon, Double lat) throws DataAccessException {
MapSqlParameterSource mappedParms = new MapSqlParameterSource("lon", lon.toString());
mappedParms.addValue("lat", lat.toString());
SqlParameterSource namedParms = mappedParms;
List<GeoCode> resultList = getSimpleJdbcTemplate().query(SELECT_STATEMENT, new GeoCodeRowMapper(), namedParms);
if (resultList == null || resultList.size() == 0) {
logger.warn("No record found in GeoCode lookup.");
}
return resultList;
}
protected static final class GeoCodeRowMapper implements RowMapper<GeoCode> {
public GeoCode mapRow(ResultSet rs, int i) throws SQLException {
GeoCode gc = new GeoCode();
gc.setCode(rs.getString(1));
gc.setType(rs.getString(2));
gc.setFips(rs.getString(3));
gc.setName(rs.getString(4));
return gc;
}
}
}
I am testing the query with this class:
public class GeoCodeServiceTest {
public static void main(String[] args) {
Double lat = 40.77599;
Double lon = -83.82322;
String[] cntxs = {"project-datasource-test.xml","locationService-context.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(cntxs);
GeoCodeServiceImpl impl = ctx.getBean("geoCodeService", GeoCodeServiceImpl.class);
List<GeoCode> geoCodes = impl.getGeoResults(lon, lat);
System.out.println(geoCodes);
}
}
I keep getting the following error:
2011-03-07 08:16:29,227 [main] DEBUG org.springframework.jdbc.support.SQLErrorCodesFactory - SQL error codes for 'PostgreSQL' found
2011-03-07 08:16:29,227 [main] DEBUG org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator - Unable to translate SQLException with SQL state 'XX000', error code '0, will now try the fallback translator
2011-03-07 08:16:29,227 [main] DEBUG org.springframework.jdbc.support.SQLStateSQLExceptionTranslator - Extracted SQL state class 'XX' from value 'XX000'
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [SELECT ste_code, ste_code_type, name, fips_code FROM "steGeo" WHERE st_contains( the_geom, ST_GeomFromText('POINT(:lon :lat)',4269))]; SQL state [XX000]; error code [0]; ERROR: parse error - invalid geometry
Hint: "POINT(" <-- parse error at position 6 within geometry; nested exception is org.postgresql.util.PSQLException: ERROR: parse error - invalid geometry
Hint: "POINT(" <-- parse error at position 6 within geometry
It looks like my parameters are not populated.
I haven't used Postgre before so any help would be much appreciated.
Thanks
Parameters are not handled inside quoted strings, so I guess you need to pass the whole string as a single parameter:
public static final String SELECT_STATEMENT =
"SELECT ste_code, ste_code_type, name, fips_code " +
"FROM \"steGeo\" " +
"WHERE st_contains( the_geom, ST_GeomFromText(:pt, 4269))";
...
MapSqlParameterSource mappedParms = new MapSqlParameterSource("pt",
"POINT(" + lon.toString() + " " + lat.toString() + ")");

Resources