Using PreparedStatement template issue - java

Here's my static utility:
//String sqlQuery = "select count(name) as num from tbname where name = ?"
//String name = "testString";
private static int correct(Connection connection, String sqlQuery, String name) {
int result = 0;
PreparedStatement statatement = null;
ResultSet rs = null;
try {
statatement = connection.prepareStatement(sqlQuery);
statatement.setString(1, name);
rs = statatement.executeQuery();
while (rs.next()) {
result = rs.getInt("num");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
statatement.close();
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
return result;
}
}
The method above returns 0 (incorrect result), but the following one returns '1' (it works OK, it the same sql query):
//String sqlQuery = "select count(name) as num from tbname where name = 'testString'"
private static int correct(Connection connection, String sqlQuery, String name) {
int result = 0;
PreparedStatement statatement = null;
ResultSet rs = null;
try {
statatement = connection.prepareStatement(sqlQuery);
rs = statatement.executeQuery();
while (rs.next()) {
result = rs.getInt("num");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
statatement.close();
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
return result;
}
}
Could you please give me any advise, so I could resolve the problem.
PS: I'm not sure if it does matter, but the actual streetName - has a name in windows-1251 encoding (Russian) text.
PPS: The database is Oracle 10.

It might be a character set issue. According to the Oracle JDBC Drivers release 10.1.0.2.0 (10g) README:
The following is a list of known
problems/limitations:
If the database character set is AL32UTF8, you may see errors under the
following circumstances:
accessing LONG and VARCHAR2 datatypes.
binding data with setString() and setCharacterStream().
So if your database character set is AL32UTF8, you might have to get it changed to something else.
Also, what is the datatype of your column? VARCHAR2?

It seems the encoding conflict with the one which you set in your DB encoding charset and the the String you are passing..
You can do these 2 tries
Set the DB encoding to UTF-8 and then give a try. If this does not work you may go with following 2nd option
Set DB encoding charset to UTF-8 and also set the String by using this String constructor String(byte[] bytes, String charsetName)

Related

Why ResultSet don't return the data from MySQL

I'm tying to get an image from MySQL database and show in a JLabel, but when I execute the query and try to get the bytes from the ResultSet it returns an empty array.
I tested the connection, and it is working, tested the query and its also working.
try {
conn = getConnection();
pst = conn.prepareStatement("select * from imagem where serial_imagem = 123658");
rs = pst.executeQuery()
if (rs.next()) {
image = rs.getBytes("img_imagem");
}
}catch (Exception e) {
e.printStackTrace();
}
The code does not close and thus leaks resources. The somewhat ugly Try-With-Resources syntax ensures closing connection, statement and result set, even on returning/exception.
One could make explicit with Optional whether the image was found in the table or not.
Optional.of also guarantees that the field in the database must not contain an SQL NULL value.
Optional<byte[]> loadImageFromDatabase(String imageM) throws SQLException {
String sql = "select img_imagem from imagem where serial_imagem = ?";
try (Connection conn = getConnection();
PreparedStatement pst = conn.prepareStatement(sql)) {
pst.setString(1, imageM);
try (ResultSet rs = pst.executeQuery()) {
if (rs.next()) {
return Optional.of(rs.getBytes(1)); // ofNullable
} else {
return Optional.empty();
}
}
}
}
Usage:
try {
Optional<byte[]> img = loadImageFromDatabase(jtextField1.getText().trim());
img.ifPresent(image -> {
...
});
} catch (SQLException e) {
There is still to remark that I personally do not often use ResultSet.getBytes, but rather getInputStream. Depends on the image size and creation code.

SQL injection issue in java code

I have below main method which shows SQL injection flaw (as string concatenation is done here) when scanned for coding standards/rules.
public static void main(String[] args) {
boolean flag = false;
String name = "";
String subName = "abhi";
try {
Class.forName("org.postgresql.Driver");
Connection c = DriverManager.getConnection("url","user", "password");
if(flag==true){
name = "LIKE '%'";
} else {
name = "= LOWER('" + subName + "')";
}
Statement s = c.createStatement();
String query = "SELECT * FROM xyz WHERE name "+name;
ResultSet rs = s.executeQuery(query);
while(rs.next()){
System.out.println(":"+rs.getString(1));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException se) {
se.printStackTrace();
}
}
I want to remove the SQL injection flaw. As my name parameter is dynamic, I cannot set it with preparedStatement. What can be a optimal solution to this?
NOTE: Using 2 different queries in if-else block will not solve the purpose as I have 7 different parameters to be set dynamically which will introduce overhead as there will be many queries.
As my name parameter is dynamic, I cannot set it with preparedStatement.
Sure you can, you just need to treat both the SQL text and the parameters dynamically at the same time.
You should also use try-with-resources, to correctly close the Connection, PreparedStatement, and ResultSet objects.
boolean flag = false;
String subName = "abhi";
try (Connection c = DriverManager.getConnection("url","user", "password")) {
String sql = "SELECT *" +
" FROM xyz" +
" WHERE name " + (flag ? "LIKE '%'"
: "= LOWER(?)");
try (PreparedStatement s = c.prepareStatement(sql)) {
if (! flag)
s.setString(1, subName);
try (ResultSet rs = s.executeQuery()) {
while (rs.next()) {
System.out.println(":"+rs.getString(1));
}
}
}
} catch (SQLException se) {
se.printStackTrace();
}
FYI: WHERE name LIKE '%' is the same as WHERE name IS NOT NULL, which is the same as no WHERE clause if the name column is not nullable.

Printing a query from a database

I am trying to access a database and print off a query.
I am trying to access a DEVICE table and print off the DEVICE_ID, but i am unsuccessful so far.
Here is my code at the moment;
public static void main(String[] args) throws FileNotFoundException {
try {
Class.forName("org.hsqldb.jdbc.JDBCDriver");
Preferences sysRoot = Preferences.systemRoot();
Preferences prefs = sysRoot.node("com/davranetworks/zebu");
url = prefs.get("dburl", "jdbc:hsqldb:E:\\eem\\eemdb");
} catch (Exception e) {
e.printStackTrace();
}
Connection c = getConnection();
try {
c.setAutoCommit(true);
Statement s = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = s.executeQuery("SELECT * FROM eem_db.device");
ResultSet deviceId = s.executeQuery("select device_id from eem_db.device");
System.out.println(deviceId);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection c = null;
try {
c = DriverManager.getConnection(url);
} catch (SQLException e) {
System.out.println("Error initialising connection" + e);
}
return c;
}
The returned value is org.hsqldb.jdbc.JDBCResultSet#1d3d68df.
I don't know what this value relates to as I was expecting 3 integer values.
Can anyone help me on this?
You have to iterate over the rows contained in the ResultSet and for each row get the column you want:
ResultSet deviceIdRS = s.executeQuery("select device_id from eem_db.device");
while(deviceIdRS.next()) {
System.out.println(deviceIdRS.getString("device_id"));
}
You must use the ResultSet getXXX method that correspond with your column type, for example, getInt, getString, getDate...
That ResultSet deviceId is actually an object contains rows of result from your sql, so you only can see the memory address when you print it out.
You need something like:
while(deviceId.next()){
System.out.print(deviceId.getInt(1));
}
s.executeQuery("select device_id from eem_db.device"); is returning a resultSet, you must find out the value from result set.
like
int device_id = resultset["deviceId"];
while (deviceId.next())
{
// Printing results to the console
System.out.println("device_id- "+ deviceId.getInt("device_id");
}
iterate object using resultset.
You are printing object of ResultSet, it won't give you the right values.
You need to iterate the loop like below
while(deviceId.next()) {
int integerValue = deviceId.getInt(1);
System.out.println("content" + integerValue)
}
deviceId.close();
s.close();

When injecting into a sql query using java, gets an error

public ArrayList<Message> searchMessages(String word) throws DaoException{
ArrayList<Message> messages = new ArrayList<>();
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = getConnection();
//String query = "SELECT * FROM messages WHERE text LIKE %?% order by date";
String query = "SELECT * FROM messages WHERE text LIKE '%?%'";
ps = con.prepareStatement(query);
ps.setString(1,word);
rs = ps.executeQuery();
while (rs.next()) {
int messageId = rs.getInt("messageId");
String text = rs.getString("text");
String date = rs.getString("date");
int memberId2 = rs.getInt("memberId");
Message m = new Message(messageId,text,date,memberId2);
messages.add(m);
//Company c = new Company(companyId, symbol, companyName, sharePrice, high, low);
//companies.add(c);
}
} catch (SQLException e) {
throw new DaoException("searchMessages(): " + e.getMessage());
} finally {
try {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (con != null) {
freeConnection(con);
}
} catch (SQLException e) {
throw new DaoException("searchMessages(): " + e.getMessage());
}
}
return messages;
}
Just explain the code a little first.It simply just searches the messages table and its field of text for whatever is supplied.I use a prepared statement to insert it into the query and run it.No matter what string i supply it gives this error
oow_package.DaoException: searchMessages(): Parameter index out of range (1 > number of parameters, which is 0).
No idea why it isn't working in the slightest. Would appreciate any help.
You can't use such a parameter in a prepared statement. The query should be
SELECT * FROM messages WHERE text LIKE ?
And you should use
ps.setString(1, "%" + word + "%");
I'm no expert, but i'd say your prepared statement is recognized with no parameters, and you still insert one (word)... maybe the trouble comes from the % sign?
EDIT: agree with the guy above... seems legit.

Problem using generics in function

I have this functions and need to make it one function. The only difference is type of input variable sourceColumnValue. This variable can be String or Integer but the return value of function must be always Integer.
I know I need to use Generics but can't do it.
public Integer selectReturnInt(String tableName, String sourceColumnName, String sourceColumnValue, String targetColumnName) {
Integer returned = null;
String query = "SELECT "+targetColumnName+" FROM "+tableName+" WHERE "+sourceColumnName+"='"+sourceColumnValue+"' LIMIT 1";
try {
Connection connection = ConnectionManager.getInstance().open();
java.sql.Statement statement = connection.createStatement();
statement.execute(query.toString());
ResultSet rs = statement.getResultSet();
while(rs.next()){
returned = rs.getInt(targetColumnName);
}
rs.close();
statement.close();
ConnectionManager.getInstance().close(connection);
} catch (SQLException e) {
System.out.println("Заявката не може да бъде изпълнена!");
System.out.println(e);
}
return returned;
}
// SELECT (RETURN INTEGER)
public Integer selectIntReturnInt(String tableName, String sourceColumnName, Integer sourceColumnValue, String targetColumnName) {
Integer returned = null;
String query = "SELECT "+targetColumnName+" FROM "+tableName+" WHERE "+sourceColumnName+"='"+sourceColumnValue+"' LIMIT 1";
try {
Connection connection = ConnectionManager.getInstance().open();
java.sql.Statement statement = connection.createStatement();
statement.execute(query.toString());
ResultSet rs = statement.getResultSet();
while(rs.next()){
returned = rs.getInt(targetColumnName);
}
rs.close();
statement.close();
ConnectionManager.getInstance().close(connection);
} catch (SQLException e) {
System.out.println("Заявката не може да бъде изпълнена!");
System.out.println(e);
}
return returned;
}
No you don't need to use generics for this.. generic should be used when your supported Types can be to many and you don't know about them before hand and they share something common in them.
Only for just two Types Generics is not a good choice. Using objects can be a better choice.
May be i will say you don't even need to merge these functions, that's what polymorphism is for. keeping things discreet will allow more readability of code
No need to use generic, you can just use Object as the variable type for the function :
public Integer selectIntReturnInt(String tableName, String sourceColumnName, Object sourceColumnValue, String targetColumnName) {
Integer returned = null;
String query = "SELECT "+targetColumnName+" FROM "+tableName+" WHERE "+sourceColumnName+"='"+sourceColumnValue.toString()+"' LIMIT 1";
try {
Connection connection = ConnectionManager.getInstance().open();
java.sql.Statement statement = connection.createStatement();
statement.execute(query.toString());
ResultSet rs = statement.getResultSet();
while(rs.next()){
returned = rs.getInt(targetColumnName);
}
rs.close();
statement.close();
ConnectionManager.getInstance().close(connection);
} catch (SQLException e) {
System.out.println("Заявката не може да бъде изпълнена!");
System.out.println(e);
}
return returned;
}
You don't need to use generics. Just declare it as
public Integer selectReturnInt(String tableName,
String sourceColumnName,
Object sourceColumnValue,
String targetColumnName) {
...
}
For the love $deity please don't use dynamic SQL. You will get injection vulnerabilities.
You want to break this into (at least) three method. One with the bulk of the implementation, and one each for the different types.
Also of note:
Resource handling should be of the form final Resource resource = acquire(); try { ... } finally { resource.release(); }, or in JDK7 try (final Resource resource = acquire()) { ... }.
Singletons are the work of the devil.
Exception handling considered a good idea, whereas sinking to a printf is bad.
You're probably better off only returning a value if there is exactly one result set and throwing an exception otherwise.
Have the second method just call the first:
public Integer selectIntReturnInt(String tableName, String sourceColumnName, Integer sourceColumnValue, String targetColumnName) {
return selectReturnInt(tableName, sourceColumnName, sourceColumnValue.toString(), targetColumnName);
}

Categories