Execution of SQL statement in Java function - java

I have to read the below SQL statement from one properties.
update scoreconfig set scorestatus=0 where scoreversion=props.getProperty("scoreversion");
And value for score version I've to take it from other properties file.
But, when I prepare a statement in java function as below:
final String query = strLine;
PreparedStatement ps=con.prepareStatement(query);
where query has
update scoreconfig set scorestatus=0 where scoreversion=props.getProperty("scoreversion");
But I get
Error: ORA-00911: invalid character
...when I do ps.execute();

I assume props is a Properties instance or similar. If so, the props.getProperty("scoreversion") part is meant to happen at the Java layer, not in the database. Instead:
String sql = "update scoreconfig set scorestatus=0 where scoreversion=?";
PreparedStatement ps = con.prepareStatement(sql);
// If scoreversion is a String:
ps.setString(1, props.getProperty("scoreversion"));
ResultSet rs = ps.executeQuery();
...or if scoreversion is an int, use this instead of the setString line:
// It scoreversion is an int:
ps.setInt(1, Integer.parseInt(props.getProperty("scoreversion")));
...etc., convert as appropriate.
Basically, when you use prepareStatement, you use ? where parameters should go, and then you use setXyz on the PreparedStatement instance to set those parameters. (Oddly, they start with 1, not 0.) Note that even when the parameter is a String, you don't put quotes around it in the SQL you pass into prepareStatement; that's handled for you (along with properly escaping that string to prevent SQL injection, so PreparedStatement and setXyz are your friends, you'll get to know them well).

Related

error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? or tel=?' at line 1

Here's my query:
select *
from reg
where indexno=?
or tel=?
And here's my code:
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con =DriverManager.getConnection("jdbc:mysql://url","unam","pass");
String query = "select * from reg where indexno= ? or tel=?";
PreparedStatement ps = con.prepareStatement(query);
ps.setString(1, in.getText());
ps.setString(2, tl.getText());
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
Let's take a closer look at what your code is doing.
Connecting to the database:
Connection con =DriverManager.getConnection("jdbc:mysql://url","unam","pass");
Creating the SQL query:
String query = "select * from reg where indexno= ? or tel=?"`;
Creating a prepared statement:
PreparedStatement ps = con.prepareStatement(query);
Setting some bind parameter values:
ps.setString(1, in.getText());
ps.setString(2, tl.getText());
Creating a whole new non-prepared statement (wait, what? Why are we not using the prepared statement we spent some time creating?):
Statement st = con.createStatement();
Using the new non-prepared statement to execute the SQL query.
ResultSet rs = st.executeQuery(query);
As a result of the last two lines, your SQL query is sent straight to the MySQL database. MySQL doesn't understand what the ? marks are for, and hence complains with a syntax error about them.
When handling prepared statements, JDBC drivers will either replace the ? marks with the database's own syntax for bind parameters (unless the database supports ? marks directly, but not all databases do), or put the values directly in the SQL string after suitable escaping of any characters, before they send the SQL to the database. Statements don't support bind parameters, and will just send the SQL string they are given straight to the database.
Your code creates a PreparedStatement and sets two bind parameter values. It seems a shame not to actually use your prepared statement once you've created it. You can get the result set you want out of it by calling ps.executeQuery(). There is no need for the separate Statement you created by calling connection.createStatement().
The fix therefore is to remove the last two lines of the code in your question and add the following line in place of them:
ResultSet rs = ps.executeQuery();

Using MySQL select in Java as String

I have problem with executing query in my Java program. Here is the code:
String selected=offersList.getSelectedValue();
String sql="SELECT * from outcoming_offers where about='"+selected+"'";
pst=con.prepareStatement(sql);
rs=pst.executeQuery();
And when there is single quotes in 'selected' - it is giving me an error:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near.....
So I understand why there is error but I am wondering how to make this work. Are there any other ways except concat()?
It's always better approach is to use prepared statements instead of raw SQL string concatenation.
From your example you should write prepared query like below (parameter to pass are replaced with question marks):
String sql="SELECT * from outcoming_offers where about=?";
PreparedStatement ps = con.preparedStatement(sql);
And then just inject parameter values and execute query:
ps.setString(1, selected);
ResultSet rs = ps.executeQuery();
Thanks to this approach you don't have to deal with SQL query string and single quotes, which is very often error-prone and also (very important) your code is not expose to SQL Injection attacks.
More info in documentation: https://docs.oracle.com/javase/8/docs/api/java/sql/package-summary.html
You are using a Prepared Statement but not passing the required parameter as you should. Change the statement to this:
String sql="SELECT * from outcoming_offers where about=?";
and then pass the parameter:
pst=con.prepareStatement(sql);
pst.setString(1, selected);
This way you set selected as the 1st parameter of the Prepared Statement.
Now you can execute the query:
rs=pst.executeQuery();

Is this piece of code SQL Injection safe?

Does this prevent SQL injection or do I have to pass the parameter with preparedStatement.setString()
String sqlQuery = "select st from master where st_id= %1s ";
sqlQuery = String.format(sqlQuery, id);
preparedStatement = conn.prepareStatement(sqlQuery);
rs = preparedStatement.executeQuery();
This is not a code review, the code above is an example for the question.
You are directly embedding user input in SQL code right here:
String.format(sqlQuery, id)
Effectively running user input as code. So, no, this is not safe from SQL injections. This is the definition of SQL injections.
Instead of directly embedding user input into the SQL code, use parameters in a prepared statement to treat user input as values rather than as code. Essentially the query would become this:
String sqlQuery = "select st from master where st_id= ? ";
Then you'd use the tooling in the language to add the parameter value to the query:
preparedStatement = conn.prepareStatement(sqlQuery);
preparedStatement.setInt(1, id); // <--- here
rs = preparedStatement.executeQuery();
Side note: Some may point out that if id is a non-string type then this code would still be safe from SQL injections, because nobody could inject anything dangerous as a number for example. While that may be circumstantially true for any given instance of this, it's not guaranteed and still not safe practice.
Always treat user input as values, not as code. Regardless of the type of that input or how sure you may otherwise be of the source of that input. Don't give an attacker any avenue of attack, even if you can't think of any way in which they can exploit it.

Which way is better for update database record?

I have two method for update:
String query = "update mytable set name = 'new_value' where id ='20' ";
Connection conn;
PreparedStatement pState;
try {
conn = DriverManager.getConnection(dbUrl, "root", "2323");
pState = conn.prepareStatement(query);
pState.executeUpdate();
} catch (SQLException sql) {
sql.printStackTrace();
}
OR:
String query = "update mytable set name = ?" + "where id = ?";
Connection conn;
PreparedStatement pState;
int s;
try {
conn = DriverManager.getConnection(dbUrl, "root", "2323");
pState = conn.prepareStatement(query);
pState.setStringt(1, "new_value");
pState.setString(2, "20");
s = pState.executeUpdate(); // if s = 1 then update done successfully
} catch (SQLException sql) {
sql.printStackTrace();
}
Both methods update database record correctly, Which is better?
Second approach is good practice to avoid SQL Injection attacks.
And following is enough to construct query String, another + concatenation is not required.
String query = "update mytable set name = ? where id = ?";
I would say the second approach.
You aren't returning anything, so why create a result set and go down that path?
Edit:
Even after your comment, I would still use the second template. It's more flexible. Additionally, it's faster. The PreparedStatement is pre-compiled in the database which allows the database to execute a parametric query using the statement faster than a normal query. This won't happen if you use string concatenation (like in your first example).
See: http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html
Additionally, from that page:
The main feature of a PreparedStatement object is that, unlike a
Statement object, it is given a SQL statement when it is created. The
advantage to this is that in most cases, this SQL statement is sent to
the DBMS right away, where it is compiled. As a result, the
PreparedStatement object contains not just a SQL statement, but a SQL
statement that has been precompiled. This means that when the
PreparedStatement is executed, the DBMS can just run the
PreparedStatement SQL statement without having to compile it first.
Although PreparedStatement objects can be used for SQL statements with
no parameters, you probably use them most often for SQL statements
that take parameters. The advantage of using SQL statements that take
parameters is that you can use the same statement and supply it with
different values each time you execute it.
The second way is more faster if you use frequently the same query. Depends of the database vendor, the query is cached and the efficiency is higher than that using flat sentences. But all that depends on the implementation of the JDBC driver and the services provided by the database.
See more in Using Prepared Statements in the The Java Tutorials.

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