Java string interpreted wrongly in SQL - java

There is an string[] likely;
This array stores the name of column of database table dynamically while runtime.And the program understand the size of the likely in runtime.
Now to put this in sql query .I use a for loop for concatanation of string
for(int k=0;k<likely.length;k++)
{
temp1="\"+likely["+k+"]+\"='Likely' AND ";
temp=temp.concat(temp1);
}
if the size is 3 the final temp will look like
temp = " "+likely[0]+"='Likely' AND "+
likely[1]+"='Likely' AND "+
likely[2]+"='Likely' AND "
Now i formulate sql query as
sql ="SELECT * FROM PUNE WHERE"+temp+"Arts_And_Museum='Yes'";
But during the
ps = con.prepareStatement(sql);
this statement is compiled like
SELECT * FROM PUNE
WHERE [+likely[0]+]='Likely'
AND [+likely[1]+]='Likely'
AND [+likely[2]+]='Likely' AND Arts_And_Museum='Yes'
After deep investigation ,I came to conclusion that it interprets \" as [ or ] alternately..
As a result i get an error
How should i solve this problem?
I run a for loop and prepare a string
I am trying to write a sql syntax

This is why you should use parameterized inputs when dealing with SQL queries.
// conn refers to your database connection
PreparedStatement stmnt = null;
ResultSet rs = null;
try {
stmnt = conn.prepareStatement("SELECT * FROM tbl WHERE col > '?'");
stmnt.setInt(1, 300); //set first parameter to 300
rs = stmnt.executeQuery();
} catch(Exception ex) {
System.err.println("Database exception: " + ex.getMessage());
}

\ is a reserved character. If you want to output a quote in your string you use \".
So, this code:
temp1="\"+likely["+k+"]+\"='Likely' AND ";
Will return this string:
"+likely1]+"='Likely' AND
It seems that your sql is transforming " into [ or ]

The symbol \ is used for escaping. On doing this, you are escaping all the front characters.
Whenever you are asking for an item in array you can access it using likely[k] no need for likey["k"]
Here is how you should do it.
temp1="\\"+likely[k]+"\\='Likely' AND ";

Just change this line:
temp1="\"+likely["+k+"]+\"='Likely' AND ";
To this one:
temp1="\"" + likely[k] + "\"='Likely' AND ";

Related

Prepared Statement setString adding unnecessary single quotes to String

Background
I am trying to set the contents of an ArrayList into an IN clause in a Db2 SQL statement. I am using the PreparedStatement to build my query. This is our coding standard.
What I tried #1
I researched a couple ways to achieve this. I first tried using the setArray() as show in this question: How to use an arraylist as a prepared statement parameter The result was I was getting a error of Err com.ibm.db2.jcc.am.SqlFeatureNotSupportedException: [jcc][t4][10344][11773][3.65.110] Data type ARRAY is not supported on the target server. ERRORCODE=-4450, SQLSTATE=0A502 After this roadblock, I moved on to #2
What I tried #2
I then tried using the Apache Commons StringUtils to convert the ArrayList into a comma separated String like I needed for my IN clause. The result is that this did exactly what I needed, I have a single String with all my results separated by a comma.
The problem:
The setString() method is adding single quotes to the beginning and end of my String. I have used this many times, and it has never done this. Does anyone know if there is a way around this, or an alternative using the PreparedStatement?? If I use String concatenation my query works.
Code (explained above):
List<String> selectedStatuses = new ArrayList<String>(); //Used to store contents of scoped var
//Get Contents of Checkbox which are in the form of a List
selectedStatuses = (List) viewScope.get("selectedStatuses");
String selectedStatusesString = StringUtils.join(selectedStatuses, ",");
.... WHERE ATM_DET_ATM_STAT IN (?)";
ps.setString(1, selectedStatusesString);
Log Value showing correct value of String
DEBUG: selectedStatusesString: 'OPEN','CLOSED','WOUNDED','IN PROGRESS'
Visual of incorrect result
The quotes at the beginning and end are the problem.
For an IN clause to work, you need as many markers as you have values:
String sql = "SELECT * FROM MyTable WHERE Stat IN (?,?,?,?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, "OPEN");
stmt.setString(2, "CLOSED");
stmt.setString(3, "WOUNDED");
stmt.setString(4, "IN PROGRESS");
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Since you have a dynamic list of values, you need to do this:
List<String> stats = Arrays.asList("OPEN", "CLOSED", "WOUNDED", "IN PROGRESS");
String markers = StringUtils.repeat(",?", stats.size()).substring(1);
String sql = "SELECT * FROM MyTable WHERE Stat IN (" + markers + ")";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int i = 0; i < stats.size(); i++)
stmt.setString(i + 1, stats.get(i));
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Starting with Java 11, StringUtils is no longer needed:
String markers = ",?".repeat(stats.size()).substring(1);
Use two apostrophes '' to get a single apostrophe on DB2, according to the DB2 Survival Guide. Then call .setString().
To anyone else experiencing the issue with single quotes, I had to modify my function so that it doesn't use ? to set the value; instead, I just treat the entire query as a string:
public static void runQuery(String tableName, String columnName, int value, String whereName, String whereValue) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("UPDATE " + tableName + " SET " + columnName + " = " + value + " WHERE " + whereName + " = " + "'" + whereValue + "'")) {
ps.executeUpdate();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
Hope this helps

Get the data from mysql rows and display them separately by the ResultSet in Java

I have a mysql table user which is consisted of id, name, password and email columns.
Is there a way to create some sort of query or java code that will print in my message dialog window all of the users names.
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/mydb","root","");
String sql = "select * from user;";
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
if (rs.next()) {
val1 = rs.getString(2);
val2 = rs.getString(3);
}
value = val1 + " " + val2;
JOptionPane.showMessageDialog(null,value);
}catch(SQLException e){
JOptionPane.showMessageDialog(null, e);
}
}
This only prints the name and the surname of the first user from the table :(
I want to print them all one below another!
If I set rs.getString(5); - it gives me an error: column index out of range.
I suggest you avoid JOptionPane for this kind of code. Better to use some Frame (Swing) and display all of the users into a separate window.
The problem with your code is that variable value is lyiong outside of the loop (which must be btw while loop, as spencer said).
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/mydb","root","");
String sql = "select * from user;";
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
while (rs.next()) {
val = rs.getString(2) + " " + rs.getString(3);
value += val + " ";
}
JOptionPane.showMessageDialog(null,value);
}catch(SQLException e){
JOptionPane.showMessageDialog(null, e);
}
}
Try to avoid this type of code, use ArrayList and save in the array all of the users credentials. Then easily label it wherever you want.
You're only fetching the first row from the resultset. It sounds like you want a loop, and process every row from the resultset.
while (rs.next()) {
}
UPDATE
Q: It only gives me now the last user. Probably because it overwrites the val1 and val2 variable. I suppose somehow this should also goes into the loop..
A: Yes, it should go inside the loop. But I'd be populating a collection, rather than concatenating a String.
As a performance and maintenance note, you can avoid the messiness of the string concatenation in the Java by doing the concatenation in the SQL statement. I wouldn't use SELECT * and rely on the positions of two particular columns in the resultset.
I'd use a SQL statement like this:
SELECT CONCAT(u.first_name,' ',u.last_name) AS user_name FROM users
If I wasn't populating a collection, and I needed to concatenate a honkous string, I'd use a StringBuffer, e.g.
val = new StringBuffer(4096));
while (rs.next()) {
val.append(rs.getString("user_name"));
}
value = val.toString;

SQL Syntax in JAVA using JDBC

Statement stmt = null;
String query = "SELECT CarLot.CAR.Make, CarLot.CAR.Model, CarLot.CAR.Year, CarLot.CAR.Sold_Status, CarLot.OWNER.First_Name,CarLot.OWNER.Last_Name"+
"FROM CarLot.CAR, CarLot.OWNER" +
" WHERE CarLot.CAR.Sold_Status = TRUE";
try {
con = getConnection();
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
String heading1 = " Make"; String heading2 = " Model"; String
heading3 = " Year"; String heading4="Sold Status";
System.out.printf("%-20s %-20s %-20s %-20s\n", heading1, heading2,
heading3,heading4);
System.out.println("--------------------------------------------------------------------------\n");
while (rs.next()) {
String make = rs.getString("car.Make");
String model = rs.getString("car.Model");
int carYear = rs.getInt("car.Year");
boolean soldStatus = rs.getBoolean("car.Sold_Status");
String firstName = rs.getString("owner.First_Name");
System.out.printf("%-2s %-20s %-20s %-20s %-20s\n",
make, model, carYear,soldStatus,firstName);
}
System.out.println("\n\n");
} finally {
stmt.close();
}
The problem that I am having is a SQL syntax error, the syntax works in MySql workbench 6.0 but wont work in my Java App through JDBC, Im new to SQl and JDBC, I realize my result set may not be 100% for this query and that also may be the problem, its from a shared method, im more concerned with the SQL query statement in this case.
The problem is you are missing a space between the last selected column name and FROM. To paraphrase your query, you have:
String query = "SELECT ..., CarLot.OWNER.Last_Name"+ // oops, no space!
"FROM CarLot.CAR, CarLot.OWNER" +
" WHERE CarLot.CAR.Sold_Status = TRUE";
This error is very common, because it's hard to see a missing space at the end of a line, but there is a code style that I use to combat this - I put spaces at the start of the line, like this:
String query = "SELECT CarLot.CAR.Make, CarLot.CAR.Model, CarLot.CAR.Year, CarLot.CAR.Sold_Status, CarLot.OWNER.First_Name,CarLot.OWNER.Last_Name"+
" FROM CarLot.CAR, CarLot.OWNER" +
" WHERE CarLot.CAR.Sold_Status = TRUE";
Every line starts with quote-space, ie " ..., so now it's really obvious when a line-broken string is missing a space, and further because SQL is (generally) whitespace insensitive, you can put spaces at the end too without causing any problems.
Add a space before the FROM clause
String query = "SELECT CarLot.CAR.Make, CarLot.CAR.Model, CarLot.CAR.Year, CarLot.CAR.Sold_Status, CarLot.OWNER.First_Name,CarLot.OWNER.Last_Name" +
" FROM CarLot.CAR, CarLot.OWNER" +
" WHERE CarLot.CAR.Sold_Status = TRUE";
Aside: Consider using PreparedStatement to protect against SQL injection attacks
The first and second lines of your query don't have a space between them, so you have select ... CarLot.OWNER.Last_NameFROM CarLot... . Add the space and see what happens.

Where's my invalid character (ORA-00911)

I'm trying to insert CLOBs into a database (see related question). I can't quite figure out what's wrong. I have a list of about 85 clobs I want to insert into a table. Even when inserting only the first clob I get ORA-00911: invalid character. I can't figure out how to get the statement out of the PreparedStatement before it executes, so I can't be 100% certain that it's right, but if I got it right, then it should look exactly like this:
insert all
into domo_queries values ('select
substr(to_char(max_data),1,4) as year,
substr(to_char(max_data),5,6) as month,
max_data
from dss_fin_user.acq_dashboard_src_load_success
where source = ''CHQ PeopleSoft FS''')
select * from dual;
Ultimately, this insert all statement would have a lot of into's, which is why I just don't do a regular insert statement. I don't see an invalid character in there, do you? (Oh, and that code above runs fine when I run it in my sql developer tool.) And I if I remove the semi-colon in the PreparedStatement, it throws an ORA-00933: SQL command not properly ended error.
In any case, here's my code for executing the query (and the values of the variables for the example above).
public ResultSet executeQuery(String connection, String query, QueryParameter... params) throws DataException, SQLException {
// query at this point = "insert all
//into domo_queries values (?)
//select * from dual;"
Connection conn = ConnectionPool.getInstance().get(connection);
PreparedStatement pstmt = conn.prepareStatement(query);
for (int i = 1; i <= params.length; i++) {
QueryParameter param = params[i - 1];
switch (param.getType()) { //The type in the example is QueryParameter.CLOB
case QueryParameter.CLOB:
Clob clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION);
clob.setString(i, "'" + param.getValue() + "'");
//the value of param.getValue() at this point is:
/*
* select
* substr(to_char(max_data),1,4) as year,
* substr(to_char(max_data),5,6) as month,
* max_data
* from dss_fin_user.acq_dashboard_src_load_success
* where source = ''CHQ PeopleSoft FS''
*/
pstmt.setClob(i, clob);
break;
case QueryParameter.STRING:
pstmt.setString(i, "'" + param.getValue() + "'");
break;
}
}
ResultSet rs = pstmt.executeQuery(); //Obviously, this is where the error is thrown
conn.commit();
ConnectionPool.getInstance().release(conn);
return rs;
}
Is there anything I'm just missing big time?
If you use the string literal exactly as you have shown us, the problem is the ; character at the end. You may not include that in the query string in the JDBC calls.
As you are inserting only a single row, a regular INSERT should be just fine even when inserting multiple rows. Using a batched statement is probable more efficient anywy. No need for INSERT ALL. Additionally you don't need the temporary clob and all that. You can simplify your method to something like this (assuming I got the parameters right):
String query1 = "select substr(to_char(max_data),1,4) as year, " +
"substr(to_char(max_data),5,6) as month, max_data " +
"from dss_fin_user.acq_dashboard_src_load_success " +
"where source = 'CHQ PeopleSoft FS'";
String query2 = ".....";
String sql = "insert into domo_queries (clob_column) values (?)";
PreparedStatement pstmt = con.prepareStatement(sql);
StringReader reader = new StringReader(query1);
pstmt.setCharacterStream(1, reader, query1.length());
pstmt.addBatch();
reader = new StringReader(query2);
pstmt.setCharacterStream(1, reader, query2.length());
pstmt.addBatch();
pstmt.executeBatch();
con.commit();
Of the top of my head, can you try to use the 'q' operator for the string literal
something like
insert all
into domo_queries values (q'[select
substr(to_char(max_data),1,4) as year,
substr(to_char(max_data),5,6) as month,
max_data
from dss_fin_user.acq_dashboard_src_load_success
where source = 'CHQ PeopleSoft FS']')
select * from dual;
Note that the single quotes of your predicate are not escaped, and the string sits between q'[...]'.
One of the reason may be if any one of table column have an underscore(_) in its name . That is considered as invalid characters by the JDBC . Rename the column by a ALTER Command and change in your code SQL , that will fix .
Oracle provide some explanation for ORA-00911. You can got this explanation after executing SQL request in Oracle SQL Developer.
ORA-00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual
But in your case it seems to be double ' character

SQL Where Clause with Values Provided

I am trying to use a SQL Select statement for a query in Java. I currently have the following:
ResultSet rs = stmt.executeQuery("SELECT *" +
" FROM " + table +
" WHERE " + selection +
" VALUES " + selectionArgs);
where "selection" is a string and "selectionArgs" is a string array.
String selection = "documentFK=?";
String[] selectionArgs = { ... };
Is it possible to use the VALUES command to replace the ? like in with the INSERT command? Either way, what would be the correct syntax?
Thanks for the help.
I believe what you're looking for is the IN statement. Your query should look like this:
SELECT *
FROM table
WHERE documentFK IN ('doc1', 'doc2', 'doc3')
AND userFK IN ('user1', 'user2', 'user3')
This is (obviously) going to make your code a bit more ugly. You'll have to ensure that the WHERE keyword is used for the first clause, but the AND keyword is used for every other clause. Also, each list will have to be comma-delimited.
no, that is not the way it's done. first you create the statement from the query, using the question marks as place holders for the real values you want to put there. then you bind these values to the statement.
//the query
String sql = "SELECT " + "*" +
" FROM " + table +
" WHERE documetFK = ?";
//create the statement
PreparedStatement stmt = connection.prepareStatement(sql);
//bind the value
stmt.setInt(1, 4); //1 is "the first question mark", 4 is some fk
//execute the query and get the result set back
ResultSet rs = stmt.executeQuery();
now, if you want this thing with selection string and some args, then you're going to have a loop in your java code. not sure what your array looks like (you're not giving me that much to go on), but if it's made up from strings, it would be something like this:
//the query
String sql = "SELECT " + "*" +
" FROM " + table +
" WHERE " + selection;
//create the statement
PreparedStatement stmt = connection.prepareStatement(sql);
//bind the values
for(int i = 0; i < selectionArgs.length; i++) {
stmt.setString(i, selectionArgs[i]); //i is "the nth question mark"
}
//execute the query and get the result set back
ResultSet rs = stmt.executeQuery();
Can you use a PreparedStatement?
First of all SELECT .. WHERE .. VALUES is incorrect SQL syntax. Lose the VALUES part.
Then you're looking for prepared statements.
In your example it's going to look something like this:
String sql = "SELECT * FROM myTable WHERE documentFK=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "myDocumentFK"); // parameters start from 1, not 0. also we're assuming the parameter type is String;
ResultSet rs = pstmt.executeQuery();
Or with multiple parameters:
String sql = "SELECT * FROM myTable WHERE documentFK=? AND indexTerm=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "myDocumentFK"); // parameters start from 1, not 0. also we're assuming the parameter type is String;
pstsm.setInt(2, 100); // assume indexTerm can be 100 and is an integer
ResultSet rs = pstmt.executeQuery();
However, all of this doesn't worth your while since you can simply do the same by concatenating the value into the statement. But be aware of the SQL injections, so don't forget to escape the parameters that you're passing into the database.
PS: I was typing this way too long. You already have the answers :-)
As a side note, you may want to take a look at this to prevent SQL injections:
https://www.owasp.org/index.php/Preventing_SQL_Injection_in_Java
Sormula can select using "IN" operator from a java.util.Collection of arbitrary size. You write no SQL. It builds the SQL SELECT query with correct number of "?" parameters. See example 4.

Categories