java.sql.SQLException: operation cannot be mixed with Oracle-style batching - sql

I'm not really sure about the mixing JDBC and Oracle batching... I read that I can't mix it on one instance of preparedStatment ... because of: Oracle Update Batching Models - Using both batching models in same application
But I also find something saying that it can't be mixed even in a single application... http://docs.oracle.com/cd/B10500_01/java.920/a96654/oraperf.htm
So know I'm not sure where the problem is...
I create a new prepared statment in each call of function:
public void functionCall(int Id)
PreparedStatement insStm = null;
String featureName = "";
String featureTypeName = "";
String sql = "BEGIN insert into " + TABLE_FEATURE_INSET + " values (?, ?, ?, ?); EXCEPTION WHEN others THEN IF SQLCODE != -1 THEN RAISE; END IF; END;";
insStm = getConnection().prepareStatement(sql);
for(xxx)
for (yyy) {
for (zzz) {
insStm.setObject(1, TypeName);
insStm.setObject(2, tableName);
insStm.setObject(3, sourceId);
insStm.setObject(4, Id);
insStm.addBatch();
}
}
// per feature
insStm.executeBatch();
}
statement .close();
}
And then I sometimes get an error...:
Caused by: java.sql.SQLException: operation not allowed: operation
cannot be mixed with Oracle-style batching
Maybe is problem that prepareStatment can be from same connection? I'm really not sure about this.
Can somebody help me? Thanks
EDIT:
That error is caused by this call: insStm.addBatch();

Related

SQL error Column count doesn't match value count at row 1

Am I missing an error with the following to insert into a table with four columns, message_id (auto-incremented) message_sender, message_reciever, message_body. I have checked similar questions and haven't found the solution.
'''
<% String sender_id = request.getParameter("message_sender");
String reciever_id = request.getParameter("message_reciever");
String message = request.getParameter("message_body");
try{
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/fyp", "root", "Kmd116352323!");
Statement st = con.createStatement();
st.executeUpdate("INSERT INTO messages(message_sender,message_reciever,message_body) VALUES('"+sender_id+", "+reciever_id+" , "+message+" ')");
out.println("Your request has been noted."
+ " Please return to your user profile or log out");
} catch(Exception e){
out.println(e);
}
%>
You should not concatenate values into a query string. It makes your code vulnerable to SQL injection, or mistakes like forgetting quotes around values. The specific problem in your case is that you have a quote before the first value and a quote after the last value, which makes it a single value instead of three separate values.
However, instead of fixing the immediate problem by adding those missing quotes, you should switch to using a prepared statement:
try (PreparedStatement pstmt = connection.prepareStatement(
"INSERT INTO messages(message_sender,message_reciever,message_body) VALUES(?, ?, ?)") {
pstmt.setString(1, sender_id);
pstmt.setString(2, reciever_id);
pstmt.setString(3, message);
pstmt.executeUpdate();
}
As an aside, you really should not put data access in a JSP. It belongs in a DAO or service class.
This is incorrect:
VALUES('"+sender_id+", "+reciever_id+" , "+message+" ')
You have a ' wrapping the all the values... Which means sql will think you are only sending 1 value. If they are all text values it should be like this:
VALUES('"+sender_id+"', '"+reciever_id+"' , '"+message+"')
If you know some of the values are of INT type then you do not need the ' for that value:
VALUES("+sender_id+", "+reciever_id+" , '"+message+"')
Text values need to be wrapped with a '

How to set large string as param without getting ORA-01460: unimplemented or unreasonable conversion error?

In spring-boot using namedParameterJdbcTemplate (Oracle db version 12 and odbc8 driver 12.2)
I am getting the following error while executing a SELECT query bound with a parameter larger than 4000 character whereas update queries working fine.
ORA-01460: unimplemented or unreasonable conversion requested
The unit test I am trying to execute;
#Test
public void testSqlSelectQueryLargeStringParameter() {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("param", theLargeStr);
// #formatter:off
String sql =
"SELECT NULL id, NULL text FROM DUAL WHERE 'X' != :param ";
// #formatter:on
namedParameterJdbcTemplate.queryForRowSet(sql, params);
}
Is there any way to set this large param via MapSqlParameterSource?
I am #ahmet-orhan 's colleague, we've found a solution.
Thanks #kfinity for your suggestion, It is working for insert and update but we are still getting this error when we set clob or blob as "paremeter" in select statements.
If using a driver that supports JDBC4.0, the right solution is create a DefaultLobHandler and set streamAsLob or createTemporaryLob to true.
MapSqlParameterSource params = new MapSqlParameterSource();
String myString = "";
for (int i = 0; i < MAX_CLOB_BLOB_SIZE_IN_SELECT; i++) {
myString = myString + "1";
}
DefaultLobHandler lobHandler = new DefaultLobHandler();
lobHandler.setStreamAsLob(true);
params.addValue("param", new SqlLobValue(myString, lobHandler), Types.CLOB);
// #formatter:off
String sql =
"SELECT 1 id FROM DUAL WHERE :param IS NOT NULL ";
// #formatter:on
Integer id = namedParameterJdbcTemplate.queryForObject(sql, params, Integer.class);
We prefer streamAsLob but to be honest we have no idea which one is better.
This comment points out that ORA-01460 in JDBC queries is the same as "ORA-01704: string literal too long". (You can't have string literals longer than 4000 characters.) Maybe try this solution?
params.addValue("param", theLargeStr, Types.CLOB);
Although also != won't work for clob comparison, so you'll also need to change your query to
SELECT NULL id, NULL text FROM DUAL WHERE dbms_lob.compare('X',:param) != 0

ActiveJDBC batch insert and transaction

What is the recommended way to insert a batch of records or none if the database raises an error for any of the inserts?
Here is my current code:
PreparedStatement ps = Base.startBatch("INSERT INTO table(col1) VALUES(?)");
for (MyModel m : myModels)
Base.addBatch(ps, m.getCol1());
Base.executeBatch(ps);
ps.close();
This inserts records until the first one that fails (if happens).
I want all or nothing to be inserted, then I was thinking of wrapping the executeBatch():
Base.openTransaction();
Base.executeBatch(ps);
Base.commitTransaction();
If it is correct, should I do Base.rollbackTransaction() in some try catch?
Should I also close the ps.close() in a finally block?
Thanks!
Transacted batch operations are not any different from non-batch operations. Please, see this: http://javalite.io/transactions#transacted-activejdbc-example for a typical pattern.
You will do this then:
List<Person> myModels = new ArrayList<>();
try{
Base.openTransaction();
PreparedStatement ps = Base.startBatch("INSERT INTO table(col1) VALUES(?)");
for (Person m : myModels){
Base.addBatch(ps, m.getCol1());
}
Base.executeBatch(ps);
ps.close();
Base.commitTransaction();
}catch(Exception e){
Base.rollbackTransaction();
}
This way, your data is intact in case of exceptions

get data from resultset after the execution of sql query in netbeans

I have created a table register in SQL with field username. In the JFrame when a user enters username there is a JButton for checking the username availability. For this I have used the code below:
String sqlstmt = "select username from register where username='" +
jTextField1.getText() + "'";
try {
st = con.prepareStatement(sqlstmt);
stmt = con.createStatement();
rs = st.executeQuery(sqlstmt);
if (rs.next()) {
JOptionPane.showMessageDialog(null,"found");
} else {
JOptionPane.showMessageDialog(null,"not found");
}
} catch(SQLException e) {
JOptionPane.showMessageDialog(null,"sql error");
}
when executing this query, it is seen that data is empty. Or if I put rs.getString("username") inside the if (rs.next), it shows the "sql error" message.
You're mixing Statements and PreparedStatements here.
The best approach here would probably be to use a PreparedStatement, which would take care of any funky characters from your input, and offer protection against SQL injection:
// SQL statement to prepare.
// Note the lack of single quotes (') in the parameter
String sqlstmt= "select username from register where username = ?";
// Prepare the statement
PreparedStatement st = con.prepareStatement(sqlstmt);
// Bind the argument
st.setString(1, jTextField1.getText());
// Execute
ResultSet rs = st.executeQuery();
// Rest of the code to handle results...
Note:
This example omits error handling (e.g., try-catch constructs) in favor of clarity.

ResultSet coming as empty after executing query

I have a query
SELECT instance_guid FROM service_instances WHERE service_template_guid='E578F99360A86E4EE043C28DE50A1D84' AND service_family_name='TEST'
Directly executing this returns me
4FEFDE7671A760A8DC8FC63CFBFC8316
F2F9DF641D8E2CACC03175A7A628D51D
Now I am trying same code from JDBC.
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = executionContext.getConnection();
if (conn != null) {
ps = (PreparedStatement)conn.prepareStatement(query);
if (params == null) params = new Object[0];
for (int i=0;i<params.length;i++) {
if (params[i] instanceof Integer) {
ps.setInt(i+1, ((Integer)params[i]).intValue());
} else if (params[i] instanceof java.util.Date) {
((PreparedStatement)ps).setDATE(i+1, new oracle.sql.DATE((new java.sql.Timestamp(((Date)params[i]).getTime()))));
//ps.setObject(i+1, new oracle.sql.DATE(new Time(((Date)params[i]).getTime())));
} else {
if (params[i] == null) params[i] = "";
ps.setString(i+1, params[i].toString());
}
}
rs = ps.executeQuery();
I see params[0] =E578F99360A86E4EE043C28DE50A1D84 and params[1]=TEST
But the resultSet is empty and not getting the result.I debugged but not much help?
Can you please let me know Am i trying right?
In java its defined as below
final static private String INSTANCE_GUID_BY_TEMPLATE_GUID =
"SELECT instance_guid FROM service_instances WHERE service_template_guid=? AND service_family_name=? "
SERVICE_FAMILY_NAME NOT NULL VARCHAR2(256)
SERVICE_TEMPLATE_GUID NOT NULL RAW(16 BYTE)
First and foremost this breaks every sql mapping pattern I have ever seen.
String sql = "SELECT instance_guid FROM service_instances WHERE service_template_guid=? AND service_family_name=?";
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = executionContext.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1,guid);
ps.setString(2,family);
rs = ps.executeQuery();
while(rs.next(){...}
...
}
You should not be dynamically figuring out the data types as they come in, unless you are trying to write some code to port from database X to database Y.
UPDATE
I see you are using RAW as a datatype, from this post:
As described in the Oracle JDBC Developer's guide and reference 11g,
when using a RAW column, you can treat it as a BINARY or VARBINARY
JDBC type, which means you can use the JDBC standard methods
getBytes() and setBytes() which returns or accepts a byte[]. The other
options is to use the Oracle driver specific extensions getRAW() and
setRAW() which return or accept a oracle.sql.RAW. Using these two will
require you to unwrap and/or cast to the specific Oracle
implementation class.
Further from a code readability standpoint, your solution makes it painful for a new developer to take over. Far too often I see people making sql be "dynamic" when in reality 99% of the time you don't need this level of dynamic query building. It sounds good in most people's heads but it just causes pain and suffering in the SDLC.