I'm trying to organize a search function on the site, using the Spring-jdbc NamedParameterJdbcTemplate.
public List<PhoneEntry> searchPhoneEntries(String search, String username) {
String SQL = "select * from entries, users where users.enabled=true " +
"and entries.username=:username " +
"and concat(secondName, firstName, patronymic, mobile, tel, " +
"address, entries.email) like ('%:search%')";
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("username", username);
params.addValue("search", search);
return jdbcTemplate.query(SQL, params, new PhoneEntryMapper());
}
But I get an empty list and have no any error.
When using a simple concatenation:
"...like '%" + search + "%'";
it working properly, but as I understand it is not safe.
I tried also add '%' symbols in parameter:
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("username", username);
params.addValue("search", "'%" + search + "%'");
return jdbcTemplate.query(SQL, params, new PhoneEntryMapper());
But it doesn't work too.
The solution is to add the parameter without quotes
params.addValue("search", "%" + search + "%");
and in the SQL string write
String sql = "... like :search";
Your first approach ('%:search%') did not work since named parameters are not recognized within string literals.
The second approach params.addValue("search", "'%" + search + "%'"); did not work since now the quotes were part of the like string, therefore asking Mysql to look for strings which start and end with a quote and contain the search term.
Related
I have a list of objects provided by another service which I use to update my own data. When I try to use NamedParameterJdbcTemplate.batchUpdate, all returned values are zero.
public void updateWeather(List<Weather> weatherList) {
String query = "UPDATE weather \n" +
"SET rain_probability = ROUND(:rainProbability, 4), \n" +
"wind_speed = :windSpeed \n" +
"WHERE city_id = :cityId AND date = :date;";
List<MapSqlParameterSource> batchList = new ArrayList<>();
for(Weather weather : weatherList) {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("rainProbability", weather.getRainProbability());
params.addValue("windSpeed", weather.getWindSpeed());
params.addValue("cityId", weather.getCityId());
params.addValue("date", weather.getDate());
batchList.add(params);
}
this.namedParameterJdbcParameter
.batchUpdate(query, batchList.toArray(new MapSqlParameterSource[] {});
}
If I run this UPDATE directly in the database, it works fine. Futhermore, if I run it one by one, that is, replacing values (instead of adding the parameter source to batchList) it also works.
For example:
for (Weather weather : weatherList) {
String query = String.format("UPDATE weather \n" +
"SET rain_probability = ROUND('%d', 4), \n" +
" wind_speed = %d \n" +
" WHERE city_id = :cityId AND date = :date;",
weather.getRainProbability(),
weather.getWindSpeed(),
weather.getCityId(),
weather.getDate()
);
this.namedParameterJdbcTemplate.update(query, Collections.emptyMap());
}
Any suggestions of what I'm doing wrong?
Is it the use of "\n" or the ";" at the end of the statement within the String? (I'm surprised you don't get a SQL Syntax exception with the ; inside the actual query string)
Also dates are always a bit tricky and if that isn't converting properly then your WHERE clause isn't going to match and is possibly why 0 rows are returned. Could you temporarily try converting dates to Strings and see if the count is correct (e.g. for Oracle: AND date = TO_DATE(:dateStr, 'DD/MM/YYYY') )
I am trying to change a normal query to Parameterized query using jdbcTemplate.queryForObject for avoiding SQL Injection. But the query returns EmptyResultDataAccessException - Incorrect result size: expected 1, actual 0 where the normal query works fine. Below is the normal query where i get the correct result.
StringBuilder builder = new StringBuilder();
String AcctNameBuilder = adhpDetailUtil.getAccName();
builder.append("select * " +
"from gfc.LSI_ELGBLTY " +
"where INSURANCE_ID = '" + request.getInsuranceId() + "' and " +
"SYS_CD = '" + request.getSystemId() + "' and " +
"ACCT_TYPE in (" + AcctNameBuilder.toString() + ")");
Here is the parameterized query that i have created from the above query.
StringBuilder builder = new StringBuilder();
String AcctNameBuilder = adhpDetailUtil.getAccName();
final String QUERY = "select * " + "from gfc.LSI_ELGBLTY " + "where INSURANCE_ID = ? and " + "SYS_CD = ? and " + "ACCT_TYPE in (?)";
Object[] params = new Object[] {
request.getInsuranceId(),request.getSystemId(),AcctNameBuilder};
String ids = jdbcTemplate.queryForObject(QUERY, params, String.class);
builder.append(ids)
In the first case, builder.append contains the exact query while in the second case jdbcTemplate.queryForObject is returning EmptyResultDataAccessException. What am I doing wrong here.
I don't believe you can just append ids for an "IN" clause like that.
The parameter for the "IN" clause is technically an Array. I ran into this a number of years ago and I don't think that this has ever been truly addressed.
If you think about it this is a fairly difficult problem as the query planner for preparing the statement cannot effectively bound the number of parameters.
I am new to using SQL2O with MySQL, but I am having a weird problem, where different queries return same results. Is SQL2O returning me cached results?
My code looks like this:
String sql = "SELECT * " +
"FROM report_A" +
"ORDER BY :order :sequence "+
"LIMIT :from, :limit";
int limit = 5;
int startIndex = (page-1)*limit;
String sequence = "DESC";
try(Connection con = sql2o.open()) {
if(order.contains("-")){
order = order.replace("-", "");
sequence= " ASC";
}
Query query= con.createQuery(sql)
.addParameter("from", startIndex)
.addParameter("limit", limit)
.addParameter("order", order)
.addParameter("sequence", sequence);
List<ReportA> result = query.executeAndFetch(ReportA.class);
con.close();
The 4 parameters always change, but the output remains the same. I have verified the queries in mysql workbench, the data is different, but SQL2O returns me the same set of data. Am I missing something?
Your query is invalid. It wont compile and throw an Sql2oException on execution.
The problem is, basically, that you can use parameters only for values, not for table names, column names or other keywords like "ASC". Changing those would change the structure of the query.
It's possible to construct queries with variable structure by good old string concatenation, i.e.
String sql = "SELECT * " +
"FROM report_A" +
"ORDER BY " + order " " + SEQUENCE +
"LIMIT :from, :limit";
and then
query(sql)
.addParameter("from", from)
.addParameter("limit", limit)
.executeAndFetch(...)
I'm trying to pass the email as a parameter for the SELECT SQL query in my JAVA back-end.
As i understood, for some reason it pass only "email_name" from the "email_name#email.com". (Getting this error):
Threw a SQLException creating the list of blogs.
ERROR: column "email_name" does not exist
Position: 174
There is an existed rows, which contains "email_name#email.com".
(Why "ERROR: column"? according to query it should look for a value, no?)
Here is My query:
String active_user = "email_name#email.com"; //email_name#email.com - example, active_user receive some path variable and on this particular moment(before query execution) contains exactly "email_name#email.com".
ResultSet rs = st.executeQuery("SELECT \n" +
" goods.item_title, \n" +
" goods.item_descr, \n" +
" goods.item_email,\n" +
" goods.item_images,\n" +
" goods.item_phone, \n" +
" goods.item_price \n" +
"FROM \n" +
" public.goods\n" +
"WHERE goods.owner = "+active_user+"\n" +
"ORDER BY\n" +
" goods.item_id ASC;");
So the question is - how to pass full email to query?
Try using String active_user = "'email_name#email.com'";. with single quotes. Since postgre recognized as column when you use double quotes.
You should use PreparedStatement. this is a example
Very unsafe approach, you should use PreparedStatement to avoid SQL injection. Here is existing answer
Suppose I have an execquery statement like this:
db1.execSQL("insert into "+TABLE_NAME+" values('"name"')");
where name is a string variable which contains an apostrophe. For example:
name = "tom's database";
In this case, I get an SQLITEexception near this statement. I am certain that this is because of that single quote.
How to modify this such that the statement does not cause a crash and the name get stored in the db with the single quote intact?
I read online that every such single quote has to be prefixed by another single quote.
Can someone provide the code for the same?
Duplicate question. Check How to escape unsupported character in SQLite on Android?
Use
String escapedName = DatabaseUtils.sqlEscapeString(name);
db1.execSQL("insert into "+TABLE_NAME+" values('" + escapedName + "')");
See http://developer.android.com/reference/android/database/DatabaseUtils.html#sqlEscapeString%28java.lang.String%29
Escaping the special character in the string literal works but generally it's an error prone approach. It's better to use ? placeholder and bind arguments, like this:
db1.execSQL("INSERT INTO " + TABLE_NAME + " VALUES (?)", new String[] { name });
or use insert() with ContentValues which does essentially the same.
You forgot:
To double the string apostrophes (since a apostrophes are the SQL string delimiters).
To add the + in the INSERT string to properly add the variable.
So, I'd change the above INSERT statement to:
db1.execSQL("INSERT INTO " + TABLE_NAME + " VALUES ('" + name.replace("'", "''") + "')");
You can use "PrepareStatement" to avoid problems
SQLiteStatement p = db1.compileStatement("insert into "+TABLE_NAME+" values(?)");
p.bindString(1, name);
p.execute();
Other form:
ContentValues values = new ContentValues();
values.put("name", name);
db1.insert(TABLE_NAME, null, values);