Sybase stored procedure insert limit with JDBC driver - java

I'm having issues with stored procedures that have a lot of insert statements when using Sybase's jdbc driver. After 50-60 inserts, the stored procedure stops execution and returns. See code below.
I'm using Sybase Anywhere 10 and their jconn2.jar, but have also tried jconn3.jar.
java code:
String sp = "sp_test";
Statement stmt = con.createStatement();
stmt.execute(sp);
stmt.close();
stored procedure:
create procedure dba.sp_test()
as
begin
declare #lnCount integer
select #lnCount = 1
while (#lnCount <= 1000 )
begin
insert into tableTest (pk) values (#lnCount)
select #lnCount = #lnCount + 1
end
end
After 58 inserts the procedure returns. Doing a select count(*) from tableTest afterward returns a count of 58. There are not SQLExceptions being thrown. I tried putting a begin/commit transaction around the insert, but it didn't make a difference. I've also tried the jodbc driver and it works fine, but I'm not able to use this as a solution because I've had other issues with it.

Using executeUpdate solved the problem:
String sp = "sp_test";
Statement stmt = con.createStatement();
stmt.executeUpdate(sp);
stmt.close();

I believe if you insert con.commit() immediately after stmt.execute() would work too.

Related

"x is a procedure, use "call"" when I am already using call

I'm using Postgres 12 and have written this procedure:
CREATE OR REPLACE PROCEDURE reduceStock(id INTEGER, soldQuantity INTEGER)
LANGUAGE plpgsql AS
$$
BEGIN
UPDATE inventory SET ProductStockAmount = ProductStockAmount - soldQuantity WHERE ProductID = id;
END;
$$;
It works perfectly if I open up psql on the command line and run call reduceStock(1,1);
However, calling it from my Java program as follows:
CallableStatement stmt = conn.prepareCall("{call reduceStock(?, ?)}");
stmt.setInt(1, productID);
stmt.setInt(2, quantity);
stmt.execute();
Gives me the following error:
What I've Tried
running call reduceStock(1,1); from the psql client - works perfectly
dropping the database and starting over to see if some old definition was cached - didn't work
different capitalisations, spacings of call
Any ideas would be appreciated
You need to remove the curly braces, which are the JDBC escape for calling a procedure. But because Postgres has it's own call command, they are not needed (and collides with the JDBC escape).
CallableStatement stmt = conn.prepareCall("call reducestock(?, ?)");
The curly braces around the procedure inocation ({call reduceStock(?, ?)}) mean that this is not native SQL, but rather JDBC syntax. You can read more about it here: Why do JDBC calls to stored procedures wrap the call in curly brackets?.
So calls like this still have to get translated to the native SQL by the JDBC driver. It happens that the Postgres driver, by default, treats such statements as function calls and translates them to SELECT reduceStock(?, ?) SQL query. This is not how stored procedures shall be called in Postgres. In Postgres a stored procedure call SQL is call reduceStock(?, ?).
One way to make it work would be, like #a_horse_with_no_name wrote in his answer, to remove the curly braces. This makes the statement a native call and because it's a valid Postgres SQL this is going to work. The downside is that it makes it less cross-platform as it will not work for DBs that don't support the call procname() syntax. For example this won't work for Oracle, so if you have to support multiple JDBC drivers, this is the less-preferable way to go.
A better fix would be to hint Postgres JDBC driver to treat this syntax like a stored procedure call rather than a function call and translate it to SQL accordingly. For this purpose the Postgres driver exposes a escapeSyntaxCallMode configuration property (check out the EscapeSyntaxCallMode enum as well):
Specifies how the driver transforms JDBC escape call syntax into underlying SQL, for invoking procedures or functions. (backend >= 11) In escapeSyntaxCallMode=select mode (the default), the driver always uses a SELECT statement (allowing function invocation only). In escapeSyntaxCallMode=callIfNoReturn mode, the driver uses a CALL statement (allowing procedure invocation) if there is no return parameter specified, otherwise the driver uses a SELECT statement. In escapeSyntaxCallMode=call mode, the driver always uses a CALL statement (allowing procedure invocation only).
As you can see all {call something()} statements are treated like function calls by default and always translated to SELECTs. Setting escapeSyntaxCallMode to call will make the driver translate them to call SQL statements instead. The callIfNoReturn option seems most reasonable for most use-cases as it will transform JDBC calls to stored procedure calls if no return parameter has been specified and as function calls otherwise.
You can find an example of using this setting in Postgres docs (Chapter 6. Calling Stored Functions and Procedures):
// set up a connection
String url = "jdbc:postgresql://localhost/test";
Properties props = new Properties();
// ... other properties ...
// Ensure EscapeSyntaxCallmode property set to support procedures if no return value
props.setProperty("escapeSyntaxCallMode", "callIfNoReturn");
Connection con = DriverManager.getConnection(url, props);
// Setup procedure to call.
Statement stmt = con.createStatement();
stmt.execute("CREATE TEMP TABLE temp_val ( some_val bigint )");
stmt.execute("CREATE OR REPLACE PROCEDURE commitproc(a INOUT bigint) AS '"
+ " BEGIN "
+ " INSERT INTO temp_val values(a); "
+ " COMMIT; "
+ " END;' LANGUAGE plpgsql");
stmt.close();
// As of v11, we must be outside a transaction for procedures with transactions to work.
con.setAutoCommit(true);
// Procedure call with transaction
CallableStatement proc = con.prepareCall("{call commitproc( ? )}");
proc.setInt(1, 100);
proc.execute(); proc.close();>
-- https://jdbc.postgresql.org/documentation/head/callproc.html#call-procedure-example

JDBC : Batch insert not inserting value to database

I have to execute multiple insert queries using JDBC for which I am trying to execute batch statement. Everything works fine in my code but when i try to see values in the table, the table is empty.
Here is the code :
SessionImpl sessionImpl = (SessionImpl) getSessionFactory().openSession();
Connection conn = (Connection) sessionImpl.connection();
Statement statement = (Statement) conn.createStatement();
for (String query : queries) {
statement.addBatch(query);
}
statement.executeBatch();
statement.close();
conn.close();
And the
List<String> queries
contains insert queries like:
insert into demo values (null,'Sharmzad','10006','http://demo.com','3 Results','some values','$44.00','10006P2','No Ratings','No Reviews','Egypt','Duration: 8 hours','tour','Day Cruises');
And the table structure is like:
create table demo ( ID INTEGER PRIMARY KEY AUTO_INCREMENT,supplierName varchar(200),supplierId varchar(200),supplierUrl varchar(200),totalActivities varchar(200),activityName varchar(200),activityPrice varchar(200),tourCode varchar(200),starRating varchar(200),totalReviews varchar(200),geography varchar(200),duration varchar(200),category varchar(200),subCategory varchar(200));
No exception is thrown anywhere but no value is inserted. Can someone explain?
Most JDBC drivers use autocommit, but some of them do not. If you don't know, you should use either .setAutoCommit(true) before the transaction or .commit() after it..
Could be a transaction issue. Perhaps you're not committing your transaction? If so, then it is normal not to see anything in the database.
You can check if this is the case by running a client in READ_UNCOMMITTED transaction mode, right after .executeBatch(); (but before close()) and see if there are any rows.
You don't should assign a value to ID add supply all the others columns name
insert into demo
(
supplierName
,supplierId
,supplierUrl
,totalActivities
,activityName
,activityPrice
,tourCode
,starRating
,totalReviews
,geography
,duration
,category
,subCategory
)
values (
'Sharmzad'
,'10006'
,'http://demo.com'
,'3 Results'
,'some values'
,'$44.00'
,'10006P2'
,'No Ratings'
,'No Reviews'
,'Egypt'
,'Duration: 8 hours
','tour'
,'Day Cruises'
);
and add commit to your code

Calling MS Sql server stored procedure which has cursor and temporal table in it from java?

I have one stored proc written in MS Sql Server which has cursor and temporal table in it and returns result of one select query at the end.
I am trying to call it from java with following piece of code
final Connection conn = getConnection();
final CallableStatement statement = conn.prepareCall("{call dbo.storedProcName (?) }");
statement.setString(1, "value1,value2");
final ResultSet rs = statement.executeQuery();
while (rs.next()) {
//some code
}
When I execute this code in java I get the resultset as null.
The stored proc returns values when I run it on sql server console with the same parameters I am passing from java code.
Any idea what causing this issue here?
I am using sqljdbc4.jar, Java 7 and SQL Server 2008 R2.
Error stack
com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:170)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:392)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:338)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4026)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1416)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:185)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:160)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:281)
Stored proc rough format
create procedure [dbo].[storedProcName](
#inpurparam varchar(4000)
)
as
begin
select some_values into #temp_table where value in (#inputparam)
//declare some_variables
declare #table2 table(col1 varchar(10), col2 varchar(10))
declare cursor for select * from #temp_table
open cursor
fetch next from cursor into some_params
while ##fetch_status = 0
begin
//some processing
//insert into table2 based on some logic
fetch next ..
end
close cursor
deallocate cursor
drop table #temp_table
select col1, col2 from #table2
order by col1
end
go
I was able to fix it with slight change to the stored proc.
create procedure [dbo].[storedProcName](
#inpurparam varchar(4000)
)
as
begin
**SET NOCOUNT ON**
..
..
I don't know how this fixed the issue but it is working like a charm.
I'd appreciate if anybody could throw some light on it.

Why does my code produce the error: The statement did not return a result set [duplicate]

This question already has answers here:
Execute "sp_msforeachdb" in a Java application
(3 answers)
Closed 1 year ago.
I am executing the following query from Microsoft SQL Server Studio, which works fine and displays results:
SELECT *
INTO #temp_table
FROM md_criteria_join
WHERE user_name = 'tecgaw'
UPDATE #temp_table
SET user_name = 'tec'
WHERE user_name != 'tec'
SELECT *
FROM md_criteria_join
WHERE user_name = 'tec'
AND view_name NOT IN (SELECT view_name
FROM md_criteria_join
WHERE user_name = 'tecgaw')
UNION
SELECT *
FROM #temp_table
ORDER BY view_name,
user_name,
crit_usage_seq,
crit_join_seq
However, if I execute the same query in Java, an Exception is thrown stating
The statement did not return a result set.
Here's the Java code:
statement = conn.getConnection().createStatement();
resultSet = stmt.executeQuery(sql.toString());
Is that because I cannot do multiple SQL queries in one statement (I.e., Creating the #temp_table, updating it, and then using for it my select statement)?
JDBC is getting confused by row counts.
You need to use SET NOCOUNT ON.
Use execute statement for data manipulation like insert, update and delete and
executeQuery for data retrieval like select
I suggest you to separate your program into two statements one execute and one executeQuery.
If you do not wish to do that, try separating the statements with semi-colon. But I am not sure about this action if this gives you a resultset or not.
I have found similar question in StackOverflow here. You should enable connection to support multiple statements and separate them using ;. For concrete examples see that answer. However it is for MySql only.
Also I think you can rewrite your SQL into single query
SELECT columnA, columnB, 'tec' as user_name from md_criteria_join
WHERE (
user_name = 'tec'
AND view_name NOT IN (
SELECT view_name
FROM md_criteria_join
WHERE user_name = 'tecgaw')
)
OR user_name = 'tecgaw'
ORDER BY view_name, user_name, crit_usage_seq, crit_join_seq
Another option is to move your statements to stored procedure and ivoke it from JDBC using CallableStatement
Or maybe you should try executing it with multiple jdbc statements like this
Connection conn = conn.getConnection(); //just to make sure its on single connection
conn.createStatement("SELECT INTO #temp_table").executeUpdate();
conn.createStatement("UPDATE #temp_table").executeUpdate();
conn.createStatement("SELECT ...").executeQuery();
Note you have to close resources and maybe for better performance you could use addBatch and executeBatch methods
in ms sql you also have to do set nocount on right at the beginning of the stored procedure along with terminating select / update/ insert block statement with ";"

Can not issue data manipulation statements with executeQuery() [duplicate]

This question already has answers here:
Cannot issue data manipulation statements with executeQuery()
(11 answers)
Closed 7 years ago.
I use com.mysql.jdbc.Driver
I need insert and get id.
My query:
INSERT INTO Sessions(id_user) VALUES(1);
SELECT LAST_INSERT_ID() FROM Sessions LIMIT 1;
error -
Can not issue data manipulation
statements with executeQuery()
How insert and get id?
You will need to use the executeUpdate() method to execute the INSERT statement, while you'll need to use the executeQuery() method to execute the SELECT statement. This is due to the requirements imposed by the JDBC specification on their usages:
From the Java API documentation for Statement.executeQuery():
Executes the given SQL statement, which returns a single ResultSet
object.
Parameters:
sql - an SQL statement to be sent to the database, typically a static SQL SELECT statement
and from the Java API documentation for Statement.executeUpdate():
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.
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.
Your code (pseudo-code posted here) should appear as:
statement.executeUpdate("INSERT INTO Sessions(id_user) VALUES(1)"); // DML operation
statement.executeQuery("SELECT LAST_INSERT_ID()"); // SELECT operation
And of course, the MySQL documentation demonstrates how to perform the same activity for AUTO_INCREMENT columns, which is apparently what you need.
If you need to execute both of them together in the same transaction, by submitting the statements in one string with a semi-colon separating them like the following:
statement.execute("INSERT INTO Sessions(id_user) VALUES(1); SELECT LAST_INSERT_ID() FROM Sessions LIMIT 1;");
then you'll need to use the execute() method. Note, that this depends on the support offered by the Database and the JDBC driver for batching statements together in a single execute(). This is supported in Sybase and MSSQL Server, but I do not think it is supported in MySQL.
may be you are using executeQuery() but to manipulate data you actually need executeUpdate() rather than executeQuery()
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet generatedKeys = null;
try {
connection = m_Connection;
preparedStatement = (PreparedStatement) connection.prepareStatement(qString, Statement.RETURN_GENERATED_KEYS);
// ...
int affectedRows = preparedStatement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
generatedKeys = preparedStatement.getGeneratedKeys();
int id = -1;
if (generatedKeys.next()) {
id = generatedKeys.getInt(1);
id = -1;
} else {
throw new SQLException("Creating user failed, no generated key obtained.");
}
} finally {
}
For non-select SQL statements you use ExecuteNonQuery();
To get the last inserted id, you can do this SQL statement.
SELECT LAST_INSERT_ID() AS last_id
Although there's probably an java wrapper for that select statement.
Links:
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
http://wiki.bibalex.org/JavaDoc/org/bibalex/daf/handlers/dbhandler/DBConnection.html

Categories