How to execute this Oracle statement on JDBC - java

I have trouble executing the following using a JDBC prepared statement:
CREATE OR REPLACE TRIGGER Time_trg BEFORE INSERT ON Time FOR EACH ROW
BEGIN
SELECT Time_seq.NEXTVAL INTO :new.id FROM dual;
END;
The code:
try {
PreparedStatement statement = connection.prepareStatement( sql );
preparedStatement.executeUpdate();
} finally {
statement.close();
}
I'm getting this error:
java.sql.SQLException: Missing IN or OUT parameter at index:: 1
I'm working on a database agnostic solution so I need something that is portable. So what is oracle's problem?

There is no need to write our own stored procedure to do this. Oracle provides a built-in stored procedure we can use: DBMS_UTILITY.EXEC_DDL_STATEMENT:
DBMS_UTILITY.EXEC_DDL_STATEMENT('create table t1 (id number)');
In fact this is safer than the workaround procedure suggested in the accepted answer as it doesn't allow the execution of DML and so is protected against SQL injection

Use oracle.jdbc.OraclePreparedStatement
OraclePreparedStatement statement = (OraclePreparedStatement)connection.prepareStatement( sql );
As this is much specific to Oracle, regular PrepareStatement doesn't help. Oracle provides a wrapper for the same, with additional functionalities as well.
Similarly, Oracle provides OracleCallableStatement similar to CallableStatement
WorkAround: (When PreparedStatement has to be used - Risk of being misused
CREATE PROCEDURE EXECUTE_MY_DDL(INSTRING VARCHAR2)
AS
BEGIN
EXECUTE IMMEDIATE INSTRING;
END;
Reference JavaDoc

Since you cannot have any bind variables in Oracle DDL anyway, why use a PreparedStatement? You can use a static statement instead and shouldn't run into this problem:
try (Statement s = connection.createStatement()) {
s.executeUpdate(sql);
}

Related

Select data from a temp table using java

I have a SQL stored procedure which select some data and insert to a temp table.
DECLARE #tmpTable TABLE ([record_Id] [int] NOT NULL)
WHILE(#count>0)
BEGIN
INSERT INTO #tmpTable
SELECT top 1 [record_Id]
FROM Table1
END
select * from #tmpTable
I used the following code to access the procedure
ResultSet rs=null;Statement stmt=null;
String getFirstRec="EXEC prod1";
stmt=con.createStatement();
rs=stmt.executeQuery(getFirstRec);
When I run this it gives me an error saying " the statement did not return the result set". can anyone help me to resolve this
Thanks
You want to use a CallableStatement which can be initialised from your connection using prepareCall()
Then use
CallableStatement callStat = con.prepareCall("EXEC prod1");
rs = callStat.executeQuery();
you should use prepareCall() for calling procedures
Have a look at here link
The above link clearly describes how to use procedures

execute batch with oracle prepared statement

I try to add batch prepared statement with following code:
Connection c = ...
PreparedStatement ps = c.prepareStatement(query1);
ps.setObject(....)
...
ps.addBatch(query2); // SqlException : Unsupported feature
Does not oracle jdbc driver support batches, or I am doing something wrong?
I am using oracle thin driver. Version from MANIFEST.MF Implementation-Version: 11.2.0.1.0.
java.sql.SQLException: Unsupported feature
at oracle.jdbc.driver.OraclePreparedStatement.addBatch(OraclePreparedStatement.java:9803)
at oracle.jdbc.driver.OracleStatementWrapper.addBatch(OracleStatementWrapper.java:285)
at org.jboss.resource.adapter.jdbc.WrappedStatement.addBatch(WrappedStatement.java:731)
at <application classes>
You are creating a PreparedStatement using query1 and adding query2 to an already prepared statetement of which it doesn't belong to.
If you are using PreparedStatement, I suggest using the PreparedStatement.addBatch() method instead.
PreparedStatement ps = c.prepareStatement(query1);
ps.setObject(....);
ps.addBatch(); //Voila
The JDBC specification explicitly requires PreparedStatement (and CallableStatement) implementations to throw an SQLException if you call any of the execute, executeUpdate, executeQuery or addBatch methods that accept a query string.
See for example the Javadoc on Statement.addBatch(String sql):
Throws:
SQLException - if a database access error occurs, this method is called on a closed Statement, the driver does not support batch updates, the method is called on a PreparedStatement or CallableStatement
(emphasis mine)
With PreparedStatement you can only use the setXXX methods, then use addBatch() to batch sets of parameter values for the prepared query (and repeat that for a different set of parameter values). You cannot batch different queries the way you can with a normal Statement.
The way to use batching with PreparedStatement is roughly like this:
try (PreparedStatement ps = c.prepareStatement(query1)) {
while (moreParameterValueSets) {
ps.setObject(....)
//...
ps.addBatch();
}
ps.executeBatch();
}

MySQL batch stmt with Statement.RETURN_GENERATED_KEYS

I am trying to execute 2 sql statements in a batch. the first statement is an insert that uses a auto generated value for its ID. the second statement is an insert to another table but it needs to use the auto generated value from above as part of the insert value
something like (where id is just to show the auto generated field its not defined in sql
stmt.addbatch(insert into table1("id_auto_generated", "foo"));
stmt.addbatch(insert into table2("table1_id", "boo"));
the way I do it now is by using this in my second sql
insert into table2(LAST_INSERT_ID(), "boo");
Problem is its slow even in batch statements its very slow as my batch can be 50,000 inserts.
I wanted to switch to prepared statements but do not know how to use Statement.RETURN_GENERATED_KEYS or LAST_INSERT_ID() with prepared statements.
I'm not sure this is a way you can do this with addBatch except in the manner that you are using. Another thing to try is to abandon the addBatch() method and try turning off auto-commit instead. Then you can use the stmt.getGeneratedKeys();. Something like:
connection.setAutoCommit(false);
stmt.executeUpdate("insert into table1(\"id_auto_generated\", \"foo\") ...");
DatabaseResults results = stmt.getGeneratedKeys();
// extract the id from the results
stmt.executeUpdate("insert into table2(\"table1_id\", \"boo\") ...");
... many more stmts here
connection.commit();
connection.setAutoCommit(true);
Hope this helps.

OracleCallableStatement registerOutParameter doesn't like named binding

this code gives "Incorrectly set or registered parameter" SQLException. Can anyone help please?
OracleConnection conn = getAppConnection();
String q = "BEGIN INSERT INTO tb (id) values (claim_seq.nextval) returning id into :newId; end;" ;
CallableStatement cs = (OracleCallableStatement) conn.prepareCall(q);
cs.registerOutParameter("newId", OracleTypes.NUMBER);
cs.execute();
int newId = cs.getInt("newId");
JDBC does not support named binding, so it stops here.
Either live with indexed placeholders ? or add an extra abstraction layer on top of JDBC which supports named parameters, e.g. Hibernate and/or JPA.
See also:
JDBC tutorial
Hibernate manual, chapter 10.4.1.4 - Bind Parameters
Update: The following is just for documentation purposes but not really usable, since you must set the named parameters in the order they are specified in your sql String. So it works but is very error-prone. Here goes:
I got the same error for a similar constellation using oracle jdbc drivers version 10, but it worked for me after upgrading jdbc drivers to version 11. Version 12.x also works.
My code looks something like this:
int nextIdent;
String sql = "call pkg.do_insert(:NEXT_IDENT, :SOME_COL, ...)";
try (CallableStatement stmt = conn.prepareCall(sql)) {
stmt.registerOutParameter("NEXT_IDENT", Types.INTEGER);
stmt.setString("SOME_COL", "abc");
...
stmt.execute();
nextIdent = stmt.getInt("NEXT_IDENT");
}

Overhead with Microsoft JDBC driver when executing a stored procedure

I am using Microsoft JDBC Driver 2.0 with SQL Server 2005. To explain my question better, let me start with a sample code to call a stored procedure.
public static void executeSproc(Connection con)
{
CallableStatement cstmt = con.prepareCall("{call dbo.getEmployeeManagers(?)}");
cstmt.setInt(1, 50);
ResultSet rs = cstmt.executeQuery();
while (rs.next()) {
// print results in the result set
}
rs.close();
cstmt.close();
}
Using SQL Profiler I see that the JDBC driver generates the following sql statements to make the call -
declare #P1 int
set #P1=1
exec sp_prepexec #P1 output, N'#P0 int', N'EXEC getEmployeeManagers #P0', 50
select #P1
So this means when I execute a stored procedure using a CallableStatement, the sp_prepexec
statement is called. And later when I close the statement, the sp_unprepare
is called. This seems to be the default behavior of the JDBC driver. The
problem is, the overhead to generate a prepared statement and then close it
has performance impact. Is there a way for the driver to execute the stored
procedure directly? Why can't the driver just do this -
exec getEmployeeManagers #P0=50
Try using the jTDS driver for SQLServer. I use it at work and it seems to be a lot better than the driver provided by MS.

Categories

Resources