Result set not updatable - java

I'm doing an statement with:
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
try(ResultSet results = statement.executeQuery(String.format("SELECT id, id2 FROM SETTINGS WHERE instance3 = %s, instance.getId())));
But I get this:
com.mysql.cj.jdbc.exceptions.NotUpdatable: Result set not updatable (referenced table has no primary keys). This result set must comd from a statement that was created with a result set type of ResultSet.CONCUR_UPDATABLE, the query must select one table, can not use functions and must select all primary keys from that table.
Any ideas why is this happening?

You are creating a statement that allows the result set to be updatable. A default ResultSet object is not updatable, and has a cursor that moves forward only. So you need to use the following code fragment, in which con is a valid Connection object. It illustrates how to make a result set that is scrollable and insensitive to updates by others, and that is updatable.
from : http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
you can more refer from above source document link.
PreparedStatement prepStmt= conn.prepareStatement(query,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

Related

Statement.execute always returns true for a boolean query executed from Java

When I execute a SQL query from Java and store the boolean returned, the query always returns true which shouldn't be the case at all. So I emptied the table and fired the query again, and yet it returns true for the emptied table. I have attached a picture of the table. I want the query to return true or false, so I can store it in Java. Can someone please specify an alternate code for this, please?
This is my code on java for the query.
boolean avail = st.execute("SELECT EXISTS(SELECT * from sales WHERE product='"+n+"' AND ord_date='"+sqlDate+"');");
And this is my code for result set
Statement st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
This is the table, name of the table is 'sales'
I'm new to MySQL, a more specific approach is appreciated.
Statement.execute will return true regardless of what the query returns. You are still supposed to retrieve the actual result of the query.
Returns
true if the first result is a ResultSet object; false if it is an update count or there are no results
As you execute an EXISTS statement, there will always be a result (true or false). The actual value still has to be retrieved:
You must then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s).
For reference: https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#execute-java.lang.String-String
Also note that you are directly embedding strings into your query, this will leave you vulnerable to SQL injections. Please read: How can prepared statements protect from SQL injection attacks?. Recommended reading: Introduction to JDBC
The return value of Statement.execute() signals whether the query produces a result set (true) or - possibly - an update count (false). The query you execute is a select which will always produce a result set (even if empty). In other words, it will always return true for a select.
If you want to get the result of your query, then the recommend approach is to use executeQuery. However, you are also concatenating values into your query string, which is a bad idea because it leave you vulnerable to SQL injection. The recommended approach is to switch to prepared statements:
try (PreparedStatement pstmt = con.prepareStatement(
"SELECT EXISTS(SELECT * from sales WHERE product = ? AND ord_date = ?)")) {
pstmt.setString(1, n);
pstmt.setDate(2, sqlDate);
try (ResultSet rs = st.executeQuery() {
boolean avail = rs.next() && rs.getBoolean(1);
// use avail...
}
}

How to use a PreparedStatement as a subquery in another prepared statement

I'm using a PreparedStatement in my code to make queries. For example:
PreparedStatement stmt = db.con.prepareStatement("select id from nodes where x>? and x<? and y>? and y<?");
stmt.setDouble(1, x1);
... //set a value for each param 1 thru 4
And now I have another query that wants to use the exact same query above as a subquery. So I could do:
PreparedStatement stmt2 = db.con.prepareStatement("select id from edges where startNodeId in
(select id from nodes where x>? and x<? and y>? and y<?)");
But that's repetitive and I'm likely to modify the first PreparedStatement and want those changes to propagate to the second one. Is there a way to set a prepared statement to be a subquery in another statement?
Perhaps something akin to stmt2.setPreparedStatement(2, stmt)?
Simply combine both the queries into one single SELECT statement.
SELECT x,y,z FROM tablez WHERE id IN (SELECT id FROM "your first query")

iterative update to a jdbc derby using a ResultSet [duplicate]

This question already has an answer here:
Why do I get java.sql.SQLException: ResultSet not open. Operation 'next' not permitted. java derby database?
(1 answer)
Closed 6 years ago.
In connection with another programming project, I am prototyping a JDBC project (with Netbeans, Java, and a Derby database). My program needs to iteratively update all the rows in a database table as follows:
There are three columns in the table: famousName, famousQuote, hashKey.
Originally, the famousQuote column contains a verbatim quote. I want to go down that column using a while loop, get the checksum of the ascii letters, bitwise "AND" with the hashKey value, and then replace the verbatim quote with an "encrypted" value.
As of right now, I try to extract the verbatim famousQuote using a ResultSet object, perform necessary encryption, and then an SQL statement that updates the value. All of this takes place in a while(rs.next()) loop as follows:
(pseudo-code): //all necessary database connections and variable declared here.
String sqlStatement = "Select * FROM mainTable ORDER BY famousName";
ResultSet rs = stmt.executeQuery(sqlStatement);
while(rs.next()){
tempString1 = rs.getString("famousQuote");
tempString2 = rs.getString("hashKey");
tempString3 = EncryptionAlgorithm.EncryptStatement(tempString1, tempString2);
sqlStatement = "UPDATE maintable SET famousQuote=tempString3 WHERE hashKey=tempString2";
(note, there is a bit of pseudo-code regarding the WHERE part,
but I'm sure it's immaterial to the error message I'm getting.)
stmt.executeUpdate(sqlStatement);
}
This seemed like a good idea until the program started throwing errors such as:
ResultSet not open. Operation 'next' not permitted. Verify that autoCommit is off
I later read in the documentation (concerning ResultSet):
A ResultSet object is automatically closed when the Statement object that generated it
is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
Lastly, I guess I could try moving the ResultSet rs declaration inside the while loop, so that it would instantiate a new ResultSet object, but I'm pretty sure this would lose my place in the database (re-updating the first row perpetually).
I'm now at a standstill on how to iterate my way down the table rows, executing my EncryptionAlgorithm on each quote, and then updating the column values in place.
I apologize in advance if my JDBC is a little rusty, but something like this might do the trick:
// 'conn' is your JDBC connection
Statement stmt = conn.createStatement();
PreparedStatement update = conn.prepareStatement(
"UPDATE maintable SET famousQuote=tempString3 WHERE hashKey=tempString2";
String sqlStatement = "Select * FROM mainTable ORDER BY famousName";
ResultSet rs = stmt.executeQuery(sqlStatement);
while(rs.next()){
tempString1 = rs.getString("famousQuote");
tempString2 = rs.getString("hashKey");
tempString3 = EncryptionAlgorithm.EncryptStatement(tempString1, tempString2);
update.setObject(1, tempString3);
update.setObject(2, tempString2);
update.executeUpdate(sqlStatement);
}

ResultSet update row is not working

I want to update raw in my ResultSet while I looping through the result set. Following is my code
try {
String query="SELECT * FROM smsmessage WHERE recipient = ? and sent_status = 'pending' LIMIT ? ";
PreparedStatement prepStmt = conn.prepareStatement(query);
prepStmt.setString(1,shortCode);
prepStmt.setInt(2, Integer.parseInt(batchSize));
ResultSet rs=prepStmt.executeQuery();
while (rs.next()) {
//update the selected message sent status to "sent" from "pending"
rs.updateString("sent_status","sent");
rs.updateRow();
}
} catch (SQLException e) {
log.error("MySQL exception",e);
}
What should be the possible reason for this?
I am getting following error
com.mysql.jdbc.NotUpdatable: Result Set not updatable. This result set
must come from a statement that was created with a result set type of
ResultSet.CONCUR_UPDATABLE, the query must select only one table, can
not use functions and must select all primary keys from that table.
See the JDBC 2.1 API Specification, section 5.6 for more details.This
result set must come from a statement that was created with a result
set type of ResultSet.CONCUR_UPDATABLE, the query must select only one
table, can not use functions and must select all primary keys from
that table. See the JDBC 2.1 API Specification, section 5.6 for more
details.
As the stacktrace tells, you have to create a statement that allows its resultset to be updateable:
PreparedStatement prepStmt= conn.prepareStatement(query,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
From the API of ResultSet (http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html):
A default ResultSet object is not updatable and has a cursor that moves forward only. Thus, you can iterate through it only once and only from the first row to the last row. It is possible to produce ResultSet objects that are scrollable and/or updatable. The following code fragment, in which con is a valid Connection object, illustrates how to make a result set that is scrollable and insensitive to updates by others, and that is updatable. See ResultSet fields for other options.
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");
// rs will be scrollable, will not show changes made by others,
// and will be updatable
Well, you should start by carefully reading the error text:
com.mysql.jdbc.NotUpdatable: Result Set not updatable. This result
set must come from a statement that was created with a result set
type of ResultSet.CONCUR_UPDATABLE, the query must select only one
table, can not use functions and must select all primary keys from
that table. See the JDBC 2.1 API Specification, section 5.6 for more
details.
This means that the result set is not updateable. You can't update a result set that is not updateable.
It also says that this result set must come from a statement that was created with a result set type of ResultSet.CONCUR_UPDATABLE. This means that your statement - in this case a PreparedStatement, must be created with that option.
Finally, it directs you to the documentation. JDBC 2.1 is a bit outdated, and you can find all the relevant data in the usual J2SE Documentation. Let's start from the documentation for ResultSet. It says:
A default ResultSet object is not updatable and has a cursor that
moves forward only. Thus, you can iterate through it only once and
only from the first row to the last row. It is possible to produce
ResultSet objects that are scrollable and/or updatable. The following
code fragment, in which con is a valid Connection object, illustrates
how to make a result set that is scrollable and insensitive to updates
by others, and that is updatable. See ResultSet fields for other
options.
And the code fragment it shows is:
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");
// rs will be scrollable, will not show changes made by others,
// and will be updatable
So you see, they are using a statement where you add two parameters, that enable you to scroll through the data and update it. But they are using a Statement rather than a PreparedStatement. Is this applicabe to PreparedStatement as well?
Going to the PreparedStatement documentation will not help you much, but wait, you are using the connection object to prepare the statement, perhaps it will help you?
Yes, indeed, there is a method in Connection that allows you to pass the parameters, just like the Statement in the example.
PreparedStatement prepareStatement(String sql,
int resultSetType,
int resultSetConcurrency)
throws SQLException
So now you must ask yourself, what kind of resultSetType do I need, and what kind of resultSetConcurrency?
Scrolling your statement is not necessary for your current question, so you can use the default. If you look at the documentation of the plain preparedStatement(String) you'll see:
Result sets created using the returned PreparedStatement object will
by default be type TYPE_FORWARD_ONLY and have a concurrency level of
CONCUR_READ_ONLY. The holdability of the created result sets can be
determined by calling getHoldability().
...which is why your initial prepared statement was not updatable, by the way. But anyway, it tells you that the default for the scrolling type is TYPE_FORWARD_ONLY.
What about the updating, which is the important part? Well, the options are CONCUR_READ_ONLY and CONCUR_UPDATABLE. So you need to use the second one. That's what the error message told you, after all.
Conclusion:
You need to use
PreparedStatement prepStmt = conn.prepareStatement(
query,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
This will give you an updatable result set.
And this is how to find your answer from the error message that you get.

How can I get auto generated keys and set the resultset type?

I have this SQL statement:
con = cpds.getConnection();
con.setAutoCommit(false);
SQL = "INSERT INTO person(accountID,addressID,lastName,firstName,middleName,suffix,gender,birthDate, [language], ethinicity) "
+ "VALUES(?,?,?,?,?,?,?,?,?,?)";
PreparedStatement stmt = con.prepareStatement(SQL,ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
What I want to be able to do is get the generated keys for this statement. Now I have done this before, but without setting the resultset typescroll parameter. It seems that there is no argument that does this either:
PreparedStatement stmt = con.prepareStatement(SQL,ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, Statement.RETURN_GENERATED_KEYS)
What I want to know is this: How can I set the resultset type to typescroll insensitive AND get generated keys?
Statement#getGeneratedKeys() returns a ResultSet that you can use to retrieve the keys as
ResultSet rsKeys = statement.getGeneratedKeys();
if (rsKeys.next()) {
person.setId(rsKeys.getLong(1));
}
How can I set the resultset type to typescroll insensitive AND get generated keys?
Doing this doesn't make sense because you can expect to retrieve keys only after doing an insert. While you would want to set the scroll type only for a resultset i.e. after a query. So, the two things are mutually exclusive and hence the API obviously doesn't support it.
statement.getGeneratedKeys(); would help

Categories

Resources