How to escape apostrophes from user input - java

So I'm importing information from a .csv file into a database. However I'm having trouble with the user inputted description in the csv file as they contain apostrophes which is breaking the SQL import.
My Import statement is String sqlJob =
"INSERT INTO job (ID, Job_Contact, Internal_Comment, Customer_Name,"
+ " Duration, Job_Location, Job_Completion_Date, Job_Technician,"
+ " Job_Asset, Job_Type, Job_Description) VALUES ('"
+csvRecord.get(i)+"', '"+csvRecord.get(26)+"', '"+csvRecord.get(16)
+"', '"+csvRecord.get(2)+"', '"+csvRecord.get(31)+"', '"+csvRecord.get(27)
+"', '"+csvRecord.get(28)+"', '"+csvRecord.get(29)+"', '"+csvRecord.get(30)
+"', '"+csvRecord.get(33)+"', '"+csvRecord.get(34)+"');";
A simplified form would be
"INSERT INTO job (ID, Description) VALUES ('"
+ csvRecord.get(i) + "', '" + csvRecord.get(34) + "');";
The problem is csvRecord.get(34) will sometimes contain apostrophes. For example "My name's Bob" and that apostrophe in Bob is breaking the surrounding apostrophes that are needed to declare that the value is a string for the SQL.
Is there an easy way to parse the string and add escape characters in front of apostrophes or should I format my original SQL command a different way.
Thanks!

The problem is you are assembling the SQL statement as a String, concatenating the parameter values. This is highly not advisable.
Use PreparedStatements instead that are easier to use. You can pass parameters without any modification and they won't interfere with the correct execution of the SQL statement.
Also as a valuable bonus, your code will be free of SQL Injection problems.
Example from the JDBC Tutorial:
String updateString = "update COFFEES set SALES = ? where COF_NAME = ?";
PreparedStatement updateSales = con.prepareStatement(updateString);
updateSales.setInt(1, numSales);
updateSales.setString(2, coffeeName);
updateSales.executeUpdate();
As you see, the parameters are NOT concatenated into the String, but they will take the place of the ? symbols.
Even if coffeeName has the value "Africa's Best" (apostrophe included) the query will work well.

Use PreparedStatement so you can be in save.
String name = request.getParameter( "ID" );
String message = request.getParameter( "Job_Contact" );
Connection c = null;
try
{
String url = "jdbc:mysql://localhost/**"databasename"**;
String username = "**<Database Login>**";
String password = "**<Database password>**";
**// at the ? section you can add any quantity you need to**
String sql = "insert into **<databasename>**(name, message) values (?, ?)";
c = DriverManager.getConnection( url, username, password );
PreparedStatement pstmt = c.prepareStatement( sql );
pstmt.setString( 1, name );
pstmt.setString( 2, message );
pstmt.executeUpdate();
}
catch( SQLException e )
{
throw new ServletException( e );
}
finally
{
try
{
if( c != null ) c.close();
}
catch( SQLException e )
{
throw new ServletException( e );
}
}

Related

Insert int value of Resultset in SQL-Database

I'm working with a MySQL-Server and I'm trying to select an ID from another table and insert that ID in a table but it doesn't work all the time.
Code:
public void submit() throws Exception {
Connection connection = getConnection();
Statement stmt = connection.createStatement();
Statement stmt1 = connection.createStatement();
ResultSet asset_id = stmt.executeQuery("SELECT id FROM cars.asset_type WHERE asset_type.name =" + "'" + sellables.getValue()+ "'");
while (asset_id.next()) {
System.out.println(asset_id.getInt("id"));
}
double value = parseDouble(purchased.getText());
System.out.println(value);
LocalDate localDate = purchased_at.getValue();
String insert = "INSERT INTO asset (type_id, purchase_price, purchased_at) VALUES ('"+ asset_id + "','" + value +"','" + localDate +"')";
stmt1.executeUpdate(insert);
}
I keep getting the same error message.
Caused by: java.sql.SQLException: Incorrect integer value: 'com.mysql.cj.jdbc.result.ResultSetImpl#1779d92' for column 'type_id' at row 1
There's no value in doing two client/server roundtrips in your case, so use a single statement instead:
INSERT INTO asset (type_id, purchase_price, purchased_at)
SELECT id, ?, ?
FROM cars.asset_type
WHERE asset_type.name = ?
If you really want to insert only the last ID from your SELECT query (as you were iterating the SELECT result and throwing away all the other IDs), then use this query instead:
INSERT INTO asset (type_id, purchase_price, purchased_at)
SELECT id, ?, ?
FROM cars.asset_type
WHERE asset_type.name = ?
ORDER BY id DESC -- I guess? Specify your preferred ordering here
LIMIT 1
Or with the JDBC code around it:
try (PreparedStatement s = connection.prepareStatement(
"INSERT INTO asset (type_id, purchase_price, purchased_at) " +
"SELECT id, ?, ? " +
"FROM cars.asset_type " +
"WHERE asset_type.name = ?")) {
s.setDouble(1, parseDouble(purchased.getText()));
s.setDate(2, Date.valueOf(purchased_at.getValue()));
s.setString(3, sellables.getValue());
}
This is using a PreparedStatement, which will prevent SQL injection and syntax errors like the one you're getting. At this point, I really really recommend you read about these topics!

Java JDBC with mySql - passing id from table

Here is the code:
public static Connection getConnection() throws Exception {
String name1 = "Danny";
String city1 = "Wien";
try {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/supermarket??verifyServerCertificate=false&useSSL=true";
String username = "myuser";
String password = "mypass";
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, username, password);
String sql = "insert into marketinfo "
+ " (name, country)" + " values (" + name1 + ", " + city1 + ")";
Statement insertie = conn.prepareStatement(sql);
insertie.executeUpdate(sql);
} catch (Exception e) {
System.out.println(e);
}
return null;
}
My error is "Unknown column 'Danny' in 'field list'" .
In Sql database my table contains id, name and city. I want to pass the id field because that id is incremented automatically.
There's alot going on in that code, and as others have suggested you should break it up. But actually performing the query can be done like this:
public class YourClass {
private static final String SQL = "INSERT INTO marketinfo (name, country) VALUES (?,?)";
public void addMarketInfo(String name, String city) {
try (Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(SQL)) {
stmt.setString(1, name);
stmt.setString(2, city);
stmt.executeUpdate();
} catch (SQLException e) {
// This is fine for debugging, but you probably want to log this or throw an exception
// Depends on how the rest of your application is set up
e.printStackTrace();
}
}
}
All your code creating the connection should most likely get moved to another class, and then called by the getConnection() method as in my example.
If you're using JDBC, PreparedStatements are used ALOT. It's worth looking more more examples on how they are used. Among other benefits, they're really helpful for avoiding string concatenation bugs like your original question.
This is the wrong way to do it. You should learn about PreparedStatement and how to bind values to parameters.
But it's worse than that.
Your method is getConnection, but it's also performing the query. Methods should do one thing well.
You don't close any of your resources. Another bad idea.
You print a stack trace to the console. Better to log it.
You hard wire your connection parameters instead of passing them in.
There's no connection pooling here.
seems you missed inner quotes around var name1 and city1
String sql = "insert into marketinfo "
+ " (name, country)" + " values ('"+ name1 +"', '"+ city1 +"')";
but most important you should use parametrized query instead of string concat .
To fix this you need to quote your variables in the SQL:
String sql = "insert into marketinfo "
+ " (name, country)" + " values ('"+ name1 +"', '"+ city1 +"')";
However, this is awful code, and you should not do it like this.
See here for why not: https://www.acunetix.com/websitesecurity/sql-injection/
As a hit, your sql should look like this:
String sql = "insert into marketinfo "
+ " (name, country)" + " values (:name, :city)";
Then, you use a prepared statement to set the values. Code like this is why websites get all their private information stolen.
String or varchar type should be between two quotes 'some string', but this still not secure so to avoid Syntax errors (Like you have now) or SQL Injection it's better to use PreparedStatement :
String sql = "insert into marketinfo (name, country) values (?, ?)";
try(PreparedStatement insertie = con.prepareStatement(sql);){
insertie.setString(1, name1);
insertie.setString(2, city1);
insertie.executeUpdate();
//...
}

Is it possible to insert records to MySQL with different parameter (keys & values) each time using the same insert function in Java?

I am trying to find out if it is possible to use the same insert function each time with new different parameters in java 8 & MySQL. I know it is possible in PHP as I have the PHP code below :
this is the array records:
$Customer_details=[
'firstname' => $Firstname,
'lastname'=> $lastname,
'phone' => $phone,
'email' => $email,
'password'=> $hash
];
After created the class object which is $object2 this is the records:
$object2->insert($pdo,'customer',$Customer_details);
The following code is the PHP insert function code:
function insert( $pdo, $table, $record) {
$keys = array_keys( $record);
$values = implode( ', ' , $keys);
$valuesWithColon = implode( ', :' , $keys);
$query = 'INSERT INTO ' . $table . ' (' . $values . ') VALUES (:' .
$valuesWithColon . ')' ;
$stmt = $pdo->prepare( $query);
$stmt->execute( $record);
return $stmt;
}
Can anybody just show me an example of the same thing in java, Please?
Yes, you can do that in much the same way you would achieve it with php, as #lexicore commented, a common pattern for parameterised sql queries in Java is to use PreparedStatements
Here is an example.. you would just need to wrap the code in that example in a function to make it reusable like your php example..
https://alvinalexander.com/java/java-mysql-insert-example-preparedstatement
public void insert(String fname, String lname, Date created, boolean isAdmin, int points) {
String myDriver = "org.gjt.mm.mysql.Driver";
String myUrl = "jdbc:mysql://localhost/test";
Class.forName(myDriver);
Connection conn = DriverManager.getConnection(myUrl, "root", "");
// create a sql date object so we can use it in our INSERT statement
Calendar calendar = Calendar.getInstance();
java.sql.Date startDate = new java.sql.Date(calendar.getTime().getTime());
// the mysql insert statement
String query = " insert into users (first_name, last_name, date_created, is_admin, num_points)"
+ " values (?, ?, ?, ?, ?)";
// create the mysql insert preparedstatement
PreparedStatement preparedStmt = conn.prepareStatement(query);
preparedStmt.setString (1, fname);
preparedStmt.setString (2, lname);
preparedStmt.setDate (3, created);
preparedStmt.setBoolean(4, isAdmin);
preparedStmt.setInt (5, points);
// execute the preparedstatement
preparedStmt.execute();
conn.close();
}
I wrote this about a year ago, but I think this is what your looking for.
Ibelieve youwant to changeValuesto List<Object and use a switch statement with instanceOfto parse through that.
private String insert(String tableName, List<String> columns, List<String> values){
StringBuilder stringBuilder = new StringBuilder("INSERT INTO " + tableName + " (");
for(String column :columns){
stringBuilder.append(column + ",");
}
stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(","));
stringBuilder.append(") VALUES (");
for(String value : values){
stringBuilder.append(value + ",");
}
stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(","));
stringBuilder.append(")");
return stringBuilder.toString();
}
Of as previously mention use this and make the second loop:
for(int z =0; z < columns.size(); z++){
stringBuilder.append("?,");
}
To use with PreparedStatements knowing what I know now, I would choose the latter.

Can i concatenate my String containing data with a mysql Query?

I have this code portion as :
String t = (tname2.getText());
String h = (value2.getText());
PreparedStatement ps ;
if(h.length()>2)
{
ps = con.prepareStatement("DELETE FROM "+t+" where empname = "+ h);
//ps.setString(2,h);
ps.executeUpdate();
JOptionPane.showMessageDialog(null, "Record deleted !", "Confirmation", JOptionPane.INFORMATION_MESSAGE);
}
Now, the line ps = con.prepareStatement("DELETE FROM "+t+" where empname = "+ h); isn't working . It works the other way around using "?". As like "Delete * from "+ t +" where empname =?";
and then setting the value of empname. I wanna know , if there's a way i can do things using concatenation of my empname with the query?? Can someone provide a few hints please?? `
Use PreparedStatement with a parametrized query and set the value.
This using will also prevent SQL injection.
Because concatenate values into your query make vulnerable to SQL injection.
eg.
ps = con.prepareStatement("DELETE FROM "+t+" where empname = ?");
psmt.setString(1, h);
You are missing properly opening and closing double quotes:
Try this:
ps = con.prepareStatement("DELETE FROM " + t + " where empname = '" + h + "'");

Replace Parameters in SQL query text with XXXXX

I m writing a small utility that captures and logs SQL statements, but will have to remove sensitive data from the Query text and replace with with some dummy text (i.e:XXXXX).
What is a good way to parse the SQL query in java and replace parameters value?
for example:
replace
SELECT NAME, ADDRESS, .... FROM USER WHERE SSN IN ('11111111111111', '22222222222222');
with
SELECT NAME, ADDRESS, .... FROM USER WHERE SSN IN (?, ?);
Using JSQLParser (V0.8.9) this is a solution for your problem:
String sql ="SELECT NAME, ADDRESS, COL1 FROM USER WHERE SSN IN ('11111111111111', '22222222222222');";
Select select = (Select) CCJSqlParserUtil.parse(sql);
//Start of value modification
StringBuilder buffer = new StringBuilder();
ExpressionDeParser expressionDeParser = new ExpressionDeParser() {
#Override
public void visit(StringValue stringValue) {
this.getBuffer().append("XXXX");
}
};
SelectDeParser deparser = new SelectDeParser(expressionDeParser,buffer );
expressionDeParser.setSelectVisitor(deparser);
expressionDeParser.setBuffer(buffer);
select.getSelectBody().accept(deparser);
//End of value modification
System.out.println(buffer.toString());
//Result is: SELECT NAME, ADDRESS, COL1 FROM USER WHERE SSN IN (XXXX, XXXX)
This replaces all found String values within your SQL. To replace other types of data e.g. Long values, override the corresponding visit method in ExpressionDeParser.
Don't use regexp in this case. It turns out quickly to be hard maintainable.
The correct answer depends on how much you want to replace. Something like:
[0-9]{3}-?[0-9]{2}-?[0-9]{4}
will replace social security numbers pretty well. I always take regex code to
regexpal.com
to tweak it and work out bugs.
If you need to replace tons of sensitive information though, and if there are a lot of cases, definitely start looking into using a parser to parse the SQL query string. (such as jsqlparser, as Anirudh recommended.)
String sqlDebit = select * from table where and billing_cycle_start_date between :startDate and :endDate
java:
sqlDebit= sqlDebit.replaceAll(":startDate ", ""+startDate).replaceAll(":endDate", ""+endDate);
With prepare statement you can replace "?" in your query string with your value. Use number to specify which "?" you are referring too. They go by order from right to left.
For example: "SELECT LastName, FirstName FROM Person.Contact WHERE LastName = ? and FirstName = ?"
pstmt.setString(1, "LastNameValue");
pstmt.setString(2, "FirstNameValue");
see full example below:
public static void executeStatement(Connection con) {
try(PreparedStatement pstmt = con.prepareStatement("SELECT LastName, FirstName FROM Person.Contact WHERE LastName = ?");) {
pstmt.setString(1, "Smith");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

Categories

Resources