Exec stored procedure not working with JdbcCursorItemReader - java

I need to read data from both select and exec Sybase queries using JdbcCursorItemReader in Spring-Batch. While SELECT queries run perfectly, the Exec queries are running into the following error:
Caused by: org.springframework.jdbc.UncategorizedSQLException:
Executing query; uncategorized SQLException for SQL [exec
proc_1]; SQL state
[ZZZZZ]; error code [7773]; Execute cursor 'jconnect_implicit_1' is
declared on a procedure which contains a non-SELECT or a SELECT with a
COMPUTE clause. For the declaration of this cursor to be legal it
should have a single SELECT statement without a COMPUTE clause.
; nested exception is com.sybase.jdbc4.jdbc.SybSQLException: Execute
cursor 'jconnect_implicit_1' is declared on a procedure which contains
a non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
... 43 common frames omitted
Caused by: com.sybase.jdbc4.jdbc.SybSQLException: Execute cursor
'jconnect_implicit_1' is declared on a procedure which contains a
non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
... 45 common frames omitted
The code for the JdbcCursorItemReader is as follows:
JdbcCursorItemReader itemReader = new JdbcCursorItemReader();
ColumnMapRowMapper rowMapper = new ColumnMapRowMapper();
itemReader.setDataSource(getDataSource());
itemReader.setRowMapper(rowMapper);
itemReader.setFetchSize(batchSize);
itemReader.setSql(dataSql); //datasql is passed Sybase query
Even after using StoredProcedureItemReader as suggested,
getting the following error:
Caused by: org.springframework.jdbc.UncategorizedSQLException:
Executing stored procedure; uncategorized SQLException for SQL [{call
ftsps_report(?, ?)}]; SQL state [ZZZZZ]; error code
[7773]; Execute cursor 'jconnect_implicit_1' is declared on a
procedure which contains a non-SELECT or a SELECT with a COMPUTE
clause. For the declaration of this cursor to be legal it should have
a single SELECT statement without a COMPUTE clause.
; nested exception is com.sybase.jdbc4.jdbc.SybSQLException: Execute
cursor 'jconnect_implicit_1' is declared on a procedure which contains
a non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:90)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:226)
at org.springframework.batch.item.database.AbstractCursorItemReader.doOpen(AbstractCursorItemReader.java:406)
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:144)
... 43 common frames omitted
Caused by: com.sybase.jdbc4.jdbc.SybSQLException: Execute cursor
'jconnect_implicit_1' is declared on a procedure which contains a
non-SELECT or a SELECT with a COMPUTE clause. For the declaration of
this cursor to be legal it should have a single SELECT statement
without a COMPUTE clause.
at com.sybase.jdbc4.tds.Tds.processEed(Tds.java:4112)
at com.sybase.jdbc4.tds.Tds.nextResult(Tds.java:3229)
at com.sybase.jdbc4.tds.Tds.getResultSetResult(Tds.java:3974)
at com.sybase.jdbc4.tds.TdsCursor.open(TdsCursor.java:333)
at com.sybase.jdbc4.jdbc.SybCallableStatement.sendRpc(SybCallableStatement.java:2032)
at com.sybase.jdbc4.jdbc.SybCallableStatement.execute(SybCallableStatement.java:241)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)
at com.sun.proxy.$Proxy83.execute(Unknown Source)
at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:210)
Have defined the StoredProcedureItemReader as follows:
StoredProcedureItemReader itemReader = new StoredProcedureItemReader();
ColumnMapRowMapper rowMapper = new ColumnMapRowMapper();
itemReader.setDataSource(getDataSource());
itemReader.setRowMapper(rowMapper);
itemReader.setFetchSize(batchSize);
itemReader.setProcedureName(dataSql);
SqlParameter[] parameter = {new SqlParameter("date1", Types.DATE),new SqlParameter("date2", Types.DATE)};
itemReader.setParameters(parameter);
itemReader.setPreparedStatementSetter(psSetter);
where psSetter setValues I have defined as follows:
ps.setDate(1, Date.ValueOf(paramList.get(0));
ps.setDate(2, Date.ValueOf(paramList.get(1));
I tried for few other stored procedures also and got similar issues.
Is it an error with the definition. I just want to define parameters by index preferably. Is there any straightforward way of doing so? Is it expecing the parameters in the storedproc to be named date1/date2 specifically and failing because of that?

For stored procedures, you need to use the StoredProcedureItemReader and not the JdbcCursorItemReader, something like:
#Bean
public StoredProcedureItemReader storedProcedureItemReader() {
StoredProcedureItemReader reader = new StoredProcedureItemReader();
reader.setProcedureName("yourProcedureName");
// set other properties
return reader;
}
Please refer to the reference documentation for more details.

Related

issue while executing Sybase procedure from JDBC

While executing Sybase procedure from JDBC, I am getting below error:
Execute cursor is declared on a procedure which contains a non-SELECT
or a SELECT with COMPUTE clause. for the declaration of this cursor to
be legal it should have a single select statement without a compute
clause
I am using JCONN4 sybase jar. Does sybase has such restrictions on procedure to not have select statement with compute clause?
Also I searched in Sybase documentation but couldn't get proper answer.
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.39996_1250/html/svrtsg/svrtsg348.htm
I cannot post the procedure here, but I can post the sample
create proc sample (#value_date datetime = null) as
begin
if #value_date is null
select #value_date = some_column from some_table
select a,b,c,d into #ad
from
table_a where a='something'
select a,b,c,d case when a=0 then 0 else b/a
from #ad
end
The above procedure is called using sybStatemt.executeQuery function
Looks like its Sybase bug. steps to reproduce the issue
Create a procedure having select with compute clause as i described above
write jdbc program and use belew method
statement.setFetchSize(1000);
Execute the program and you will see the error
now the question is does Sybase really has these kind of restrictions or it is specific to their Driver only and we can say its driver issue ?
You must use CallableStatement when calling store procedure
If you execute a stored procedure in a CallableStatement object that represents parameter values as question marks, you get better performance than if you use both question marks and literal values for parameters. Also, if you mix literals and question marks, you cannot use output parameters with a stored procedure.
The following example creates sp_stmt as a CallableStatement object for executing the stored procedure MyProc:
CallableStatement sp_stmt = conn.prepareCall( "{call MyProc(?,?)}");
The two parameters in MyProc are represented as question marks. You can register one or both of them as output parameters using the registerOutParameter methods in the CallableStatement interface.
In the following example, sp_stmt2 is a CallableStatement object for executing the stored procedure MyProc2.
CallableStatement sp_stmt2 = conn.prepareCall( {"call MyProc2(?,'javelin')}");
Run your sp from sybase command prompt.
If it gives result it should work with sybase driver.
I have used ado.net driver in c# it can run similar queries
https://marketplace.visualstudio.com/items?itemName=CDATASOFTWARE.SybaseADONETProvider
Your Sp looks simple. But i think your sp had some runtime issue.
I think this line
if #value_date is null
select #value_date = some_column from some_table
should be
if #value_date is null
select #value_date = some_column from some_table where col1='kkk' so that only
one value comes

Why Spring data throwing java.sql.SQLException: ResultSet is from UPDATE. No Data. on executing native mysql query

I am executing the following mysql query using spring-data-jpa,
select 'FIRM NAME', 'USER_NAME', 'EMAIL', 'USER_PHONE', 'CLICK_COUNT', 'CLICK_DATE', 'PARTNER NAME'
union all select * from (select cf.cf_firm_name, u.u_name, u.u_email, u.u_phone, co.c_clicks,
co.c_click_date, p.p_name from click_offer co inner join user u on co.c_user_id = u.u_id inner join
c_firm cf on u.u_cpa_firm = cf.cf_id inner join offer of on co.c_offer_id = of.o_id inner join
partner p on of.o_partner_id = p.p_id) a into outfile '/var/lib/mysql-files/aafa.csv' fields
terminated by ',' optionally enclosed by '"' lines terminated by '\n';
But on executing hibernate is throwing the exception after successfully creating the file,
Caused by: java.sql.SQLException: ResultSet is from UPDATE. No Data.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861)
at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:6301)
at com.zaxxer.hikari.pool.HikariProxyResultSet.next(HikariProxyResultSet.java)
at org.hibernate.loader.Loader.processResultSet(Loader.java:987)
at org.hibernate.loader.Loader.doQuery(Loader.java:949)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:341)
at org.hibernate.loader.Loader.doList(Loader.java:2692)
... 110 common frames omitted
But when I try to run the same query on mysql-workbench, it is executing without the error.
I am using the following code to execute the query from spring,
String query= DynamicQueryGenerator.queryToFetchOttomartClickCountDetails(ottoMartCsvGeneratorBean);
Query executableQuery = entityManager.createNativeQuery(query);
executableQuery.setParameter("from", fromDate);
executableQuery.setParameter("to", toDate);
if (!NullEmptyUtils.isNullorEmpty(ottoMartCsvGeneratorBean.getFirmIds())){
executableQuery.setParameter("firmIds", ottoMartCsvGeneratorBean.getFirmIds());
}
executableQuery.getResultList();
where query contains the mysql query to be executed.
Your query seems to be meant to write something into a file, not to return a resultset.
getResultList() expects results to be returned from the query.
Try calling :
executableQuery.executeUpdate()

How do I get output or error stream for jdbc

I am trying to connect DB2 via JDBC. How do I get the output message that sql would have returned as like IDE.
E.g Select query would return 100 rows were fetched.
Insert would return the number of rows updated.
Also the error messages like no rows found, User does not have privilege to access database, Insert could not be performed due to duplicate primary key etc.
catch the exception thrown and print the stack trace.
try{
// your SQL work
} catch(Exception e){
e.printStackTrace();
}
This will print the error in your output console.
Use the JDBC api execute update to get the changed row count. And the exceptions to get other messages.
https://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#executeUpdate(java.lang.String)
int executeUpdate(String sql) throws SQLException
Executes the given SQL statement, which may be an INSERT, UPDATE, or
DELETE statement or an SQL statement that returns nothing, such as an
SQL DDL statement. Note:This method cannot be called on a
PreparedStatement or CallableStatement.
Parameters: sql - an SQL Data Manipulation Language (DML) statement,
such as INSERT, UPDATE or DELETE; or an SQL statement that returns
nothing, such as a DDL statement.
Returns: either the row count
for SQL Data Manipulation Language (DML) statements or (2) 0 for SQL
statements that return nothing
Throws: SQLException - if a database
access error occurs, this method is called on a closed Statement, the
given SQL statement produces a ResultSet object, the method is called
on a PreparedStatement or CallableStatement SQLTimeoutException - when
the driver has determined that the timeout value that was specified by
the setQueryTimeout method has been exceeded and has at least
attempted to cancel the currently running Statement

Unable to fathom update count INSERT on billions of rows

I am running a Netezza SQL query that is creating a table from a select statement returning almost 8 billion rows. Here is the query:
CREATE TABLE
table1 AS
(
SELECT
column1
FROM
table2 qt
WHERE
qt.column1 = '2016-04-04'
UNION ALL
SELECT
column1
FROM
table3 qt
WHERE
qt.column1 = '2016-04-04'
)
The driver is throwing this error:
org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [UNDEFINED]; error code [0];
--- The error occurred while applying a parameter map.
--- Check the statement (update failed).
--- Cause: Unable to fathom update count INSERT 0 7779737732
Does anyone know what's causing this?
I think you are running into a JDBC driver limitation. If you run a INSERT, UPDATE, CREATE AS SELECT via JDBC and the number of rows INSERTed, UPDATEd or CREATEd exceeds 2147483647, you will receive an error message similar to the following:
Unable to fathom update count INSERT 0 5120000160
The above error message may be different given whether an INSERT, UPDATE or CREATE as SELECT and given the number of rows actually affected. This is a limitation of JDBC specification itself.
Thanks,
Sanjit

java.sql.SQLException: ORA-06550: after calling procedure from java code

Hi I have problem with calling store procedure.
when i am trying to call my procedure from my following java code
connection = ConnectionManager.getInstance().getConnection(dataBaseURL, serverName, portNumber, sid, username, password);
callable = connection.prepareCall("{call SCHEMA_RESTORE.restore()}");
callable.executeUpdate();
..................................
I am getting this Exception
Exception in thread "main" java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00201: identifier 'SCHEMA_RESTORE.RESTORE' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:573)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1891)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1093)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2047)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:1940)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2709)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:589)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:656)
My Prodedure is
CREATE OR REPLACE PACKAGE BODY SCHEMA_RESTORE IS
PROCEDURE backup (pbRecreateBackupTable IN BOOLEAN DEFAULT FALSE)
IS
TableAlreadyExists EXCEPTION;
PRAGMA EXCEPTION_INIT (TableAlreadyExists, -955);
nCount NUMBER;
CURSOR cTables IS SELECT tbls.table_name tbl, SUBSTR(tbls.table_name,4) name FROM user_tables tbls, FT_T_TBDF tbdf
WHERE tbls.table_name NOT LIKE gsPrefix || '%' AND tbls.table_name NOT LIKE 'FT_CFG%' AND tbls.table_name NOT IN ('FT_WF_APEV','FT_WF_WFTJ','FT_WF_WFTN','FT_WF_WFNP','FT_WF_WFNV','FT_WF_WFIO','FT_WF_WFGV','FT_WF_WFND','FT_WF_WFDF','EXCEPTIONS','TESTDSFP') and tbls.table_name NOT LIKE 'FT_LOG%'
AND tbdf.tbl_id(+) = SUBSTR(tbls.table_name,-4) AND tbdf.tbl_desc NOT LIKE '%Note: This table is obsolete%';
BEGIN
RAISE;
END;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END backup;
The error message says that SCHEMA_RESTORE.RESTORE cannot be found. There are several possible causes:
The package (and procedure) are in a different schema, e.g. you compiled it as user A but are trying to call them as user B.
You don't have the access right to execute procedures from the package. Thus it becomes invisible.
You have defined the procedure in the package body, but haven't declared it in the package header.
A further problem I can see are the parentheses. If you call a procedure without arguments, the prentheses shoul be omitted:
{ call SCHEMA_RESTORE.restore }
It comes when you make a procedure in one user and connect the db in another.
To solve this issue try this
GRANT EXECUTE ON procedureName TO username
Otherwise connect with correct username which you using
Did the procedure compile successfully ? Also check if you can see it via some editor (PL/SQL dev ?) under the schema
or you may use this to see if it is there -
SELECT * FROM DBA_OBJECTS WHERE object_name = '%your proc name%';

Categories