java replace ' with \' - java

I'm working with mySQL. It can not handle if ' is in the String that is being added to the database.
I tried:
replaceAll("'","\\'")
and
replaceAll("'","\'")
Any ideas how I would go about replacing ' with \'?

Don't use String replacements to handle this. Instead, use a prepared statement and thus let the JDBC driver escape the parameters for you:
String sql = "select a.foo from a where a.bar = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, aStringWhichMightContainQuotes);
ResultSet rs = stmt.executeQuery();
This is the proper way to have database-independent, robust code, that is not vulnerable to SQL injection attacks. And it also make it more efficient if you execute the same query several times with different parameters.
See the JDBC tutorial for more information.

You need to escape the backslash twice, once for the string processing engine and once for the regex engine:
replaceAll("'","\\\\'")
Caveat: While this answers the question about how to insert a backslash into a string, it certainly should not be used in an attempt to thwart SQL injection attacks.
To clarify: Imagine someone submits a string where the apostrophe is already escaped. This regex would then lead to the apostrophe being unescaped (because now the backslash would become escaped). So actually you'd need this regex to escape an apostrophe only if preceded by an even number of backslashes. This means
replaceAll("(?<!\\\\)((?:\\\\\\\\)*)'", "$1\\\\'")
This is rapidly becoming as unmaintainable as it looks, and it still doesn't cover all cases.

Related

PreparedStatement IN clause Regexp alternative?

I came across the same issue as the author of this question (PreparedStatement IN clause alternatives?), and wondered if using mysql's REGEXP would be an elegant way of getting the same functionality of IN while using only one PreparedStatement for varying number of values to match? Some example SQL here to show what I am talking about:
SELECT first_name, last_name
FROM people
WHERE first_name REGEXP ?
Multiple values could be supplied using a string like "Robert|Janice|Michael". I did not see REGEXP mentioned anywhere in that post.
Technically, yes, it is an alternative.
Note, however, that using a regex for matching is less efficient that the in operator ; it incurs more work for the database, that needs to initialize the regex engine, and run it against each and every value (it cannot take advantage of an index).You might not notice it on small volumes, but as your data grows larger this might become an issue. So I would not recommend that as a general solution: instead, just write a few more code lines in your application to properly use the in operator, and use regexes only where they are truly needed.
Aside: if you want to match the entire string, as in does, you need to surround the list of values with ^ and $, so the equivalent for:
first_name in ('Robert', 'Janice', 'Michael')
Would be:
first name regexp '^(Robert|Janice|Michael)$'
Another approach:
FIND_IN_SET(name, 'Robert,Janice,Michael')
Yes, that could be substituted in. But it must be a commalist of the desired values. This also works for FIND_IN_SET(foo, '1,123,45'). Note that 12 will not match.

Creating SQL queries with UNICODE or ASCII character codes

I would like to create a SQL query containing ASCII or UNICODE character codes in it. For example, ASCII character code for single quote (') is 39 and unicode code is U+0027. In Java, I would like to write a query by replacing the single codes with their character codes:
ASCII:
connection.createStatement().executeQuery("select * from users where name =39test39")
Unicode:
connection.createStatement().executeQuery("select * from users where name =U+0027testU+0027")
All of these queries should be equivalent to "select * from users where name ='test'"
When I run the codes above, DBMS (I tried with Mysql and SQLite) does not recognize the ascii and unicode codes as a single quote.
In summary, I know parametrized queries are the ideal. But, here in this case what I wanted to do is, when the sql code is parsed by the DBMS, then the DBMS should recognize the unicode character. For example, if I use \u0027, the JVM would recognize this as a single quote, but I want JVM to not recognize and DMBS to recognize the character encoding.
Is there any way use char codes instead of the character itself?
No, you don't want to do that. You should be doing
PreparedStatement ps = conn.prepareStatement("select * from users where name = ?");
ps.setString(1, "test");
ResultSet rs = ps.executeQuery();
Remember that all strings in Java are Unicode strings, so what you are proposing is to start sending string values as byte streams to the JDBC driver, which would be messy and error-prone (if it is even possible).
When you put the ascii/unicode numbers within double quotes they aren't resolved to characters instead try something like:
"select * from users where name =" + Character.toString(Character.toChar(yourIntHere)) + ...
And then that should build the string you are looking for
You query should look like this :
"select * from users where name =" + Character.toString((char)39) + "test" + Character.toString((char)39) + "\""

JPQL LIKE syntax with Strings

EDIT:
I changed the hard coded query to be:
query.setParameter("desc", "%unplug //your// server... enjoy the freedom%" ESCAPE '//')
and now I am getting an com.sun.jdi.InvocationException occurred invoking method.
There's no stacktrace produced either.
I have a description column in my PostgreSQL database and I am trying to query it with a 'LIKE' clause, however I am unable to get any results. Here's an example:
Query query = em.createQuery("from MyClass c WHERE c.description LIKE :desc");
query.setParameter("desc", "%unplug /your/ server... enjoy the freedom%");
In the database I have many descriptions containing a substring of the above text. I've done a lot of research and looked into escaping special chars etc, but nothing has worked.
I am missing something, I just cannot figure out what that is.
Most likely the slash / is messing up the parsing in PG. Turn the parameter into a quoted literal. Unless you are certain that no special characters go into string arguments (i.e. you control the strings), this is always a good idea to avoid SQL injection.
query.setParameter("desc", "quote_literal('%unplug /your/ server... enjoy the freedom%')");

What's wrong with my JDBC sql statement

I'm writing a java socket app that allows a client to communicate with a server, one of the other requirements is that it also needs to initialize JDBC. I believe I have wrote my JDBC connection method correctly, and my insert statement has worked like this on similar projects. It might be a simple mistake as i'm not using an IDE, can someone tell me what is wrong with my SQL statement? All the info is right, but it won't compile.
Error:
C:\Users\imallin\My Documents> javac provider.java
Provider.java:88 ';' expected
String sql = "Insert INTO 'users' ('ID', 'firstName') VALUES ("123","123")";
Your immediate problem is that you need to escape the double quotes that are in your string. This is because when the compiler see's another " it thinks it is the end of the String definition and exepcts a semi-colon.
String sql = "Insert INTO 'users' ('ID', 'firstName') VALUES (\"123\",\"123\")";
Now that the Java compiler is happy, you will have SQL-related issues.
In general with SQL, you will want to use single quotes to represent a string. It appears MySQL specifically allows double quotes, but only when the SQL QUOTES ANSI mode is not set. So it is best to use single quotes to represent strings here.
Here is what you probably want, assuming that the ID column is an integer, and that the firstName column is a string/varchar.
String sql = "Insert INTO users (ID, firstName) VALUES (123,'123')";
To slightly differ from the other answers that have been posted, you need to not use double quotes in your SQL. The single quotes you've used are all in the wrong places, and the double quotes are simply not allowed. Your statement should look like
String sql = "Insert INTO users (ID, firstName) VALUES ('123','123')";
It looks like you haven't escaped the double quotes in your SQL statement. Java sees your string as finishing before the first 123.
In the line:
String sql = "Insert INTO 'users' ('ID', 'firstName') VALUES ("123","123")";
The double quoted string ends after VALUES (, and is immediately followed by a numeric token. That's illegal in Java. The immediate fix is to add backslashes:
String sql = "Insert INTO 'users' ('ID', 'firstName') VALUES (\"123\",\"123\")";
Though this would also work (assuming it's talking about integers, not strings):
String sql = "Insert INTO 'users' ('ID', 'firstName') VALUES (" + 123 + "," + 123 + ")";
More generally though, what's wrong with it is that you're doing an INSERT without using parameterization. This is virtually always the wrong thing in real code! JDBC has good support for parameterized queries, which you should use.
You can use single quotes instead.
"Insert INTO users (ID, firstName) VALUES ('123','123')";

Java SQL Escape without using setString

Is there a built-in method to escape a string for SQL? I would use setString, but it happens I am using setString multiple times in the same combined SQL statement and it would be better performance (I think) if the escape happened only once instead of each time I say setString. If I had the escaped string in a variable, I could re-use it.
Is there no way to do this in Java?
Current method, multi-source search. In reality they are three entirely different where statements including joins, but for this example I will just show the same where for each table.
String q = '%' + request.getParameter("search") + '%';
PreparedStatement s = s("SELECT a,b,c FROM table1 where a = ? UNION select a,b,c from table2 where a = ? UNION select a,b,c FROM table3 where a = ?");
s.setString(1, q);
s.setString(2, q);
s.setString(3, q);
ResultSet r = s.executeQuery();
I know this is not a big deal, but I like to make things efficient and also there are situations where it is more readable to use " + quote(s) + " instead of ? and then somewhere down the line you find setString.
If you use setString for a parameter (e.g. PreparedStatement.setString), there may well be no actual escaping required - it's likely that the data will be passed separately from the SQL itself, in a way that doesn't require escaping.
Do you have any concrete indication that this really is a performance bottleneck? It seems very unlikely that within a database query, the expensive part is setting the parameters locally...
Short answer: I wouldn't bother. It's best to do escaping at the last popssible moment. When you try to escape a string early and keep it around, it becomes much more difficult to verify that all strings have been escaped exactly once. (Escaping a string twice is almost as bad as not escaping it at all!) I've seen plenty of programs that try to escape strings early and then run into trouble because they need to update the string and then the programmer forgets to re-do the escape, or they update the escaped version of the string, or they have four strings and they escape three of them, etc. (I was just working on a bug where a programmer did HTML escapes on a string early, then decided he had to truncate the string to fit on a form, and ended up trying to output a string that ended with "&am". That is, he truncated his escape sequence so it was no longer valid.)
The CPU time to escape a string should be trivial. Unless you have a very large number of records or very big strings that are re-used, I doubt the savings would be worth worrying about. You'd probably be better off spending your time optimizing queries: saving a read of one record would probably be worth far more than eliminating 1000 trips through the string escape logic.
Longer answer: There's no built-in function. You could write one easily enough: Most flavors of SQL just need you to double any single quotes. You may need to also double backslashes or one or two other special characters. The fact that this can be different between SQL engines is one of the big arguments for using PreparedStatements and letting JDBC worry about it. (Personally I think there should be a JDbC function to do escaping that could then know any requirements specific to the DB engine. But there isn't so that's how it is.)
In any case, it's not clear how it would work with a PreparedStatement. There'd have to be some way to tell the PreparedStatement not to escape this string because it's already been escaped. And who really knows what's happening under the table in the conversation between JDBC and the DB engine: Maybe it never really escapes it at all, but passes it separately from the query. I suppose there could be an extra parameter on the setString that says "this string was pre-escaped", but that would add complexity and potential errors for very little gain.
Do not use org.apache.commons.lang.StringEscapeUtils.escapeSql(yourUnscapedSQL);
It does not escape characters like \
You can use StringEscapeUtils from Apache commons:
org.apache.commons.lang.StringEscapeUtils.escapeSql(yourUnscapedSQL);

Categories