我正在尝试在Android中执行以下SQL查询:
String names = "'name1', 'name2"; // in the code this is dynamically generated
String query = "SELECT * FROM table WHERE name IN (?)";
Cursor cursor = mDb.rawQuery(query, new String[]{names});
Run Code Online (Sandbox Code Playgroud)
但是,Android不会使用正确的值替换问号.我可以执行以下操作,但是,这不能防止SQL注入:
String query = "SELECT * FROM table WHERE name IN (" + names + ")";
Cursor cursor = mDb.rawQuery(query, null);
Run Code Online (Sandbox Code Playgroud)
如何解决此问题并能够使用IN子句?
小智 183
表单的字符串"?, ?, ..., ?"
可以是动态创建的字符串,并安全地放入原始SQL查询中(因为它是不包含外部数据的受限形式),然后可以正常使用占位符.
考虑一个String makePlaceholders(int len)
返回len
用逗号分隔的问号的函数,然后:
String[] names = { "name1", "name2" }; // do whatever is needed first
String query = "SELECT * FROM table"
+ " WHERE name IN (" + makePlaceholders(names.length) + ")";
Cursor cursor = mDb.rawQuery(query, names);
Run Code Online (Sandbox Code Playgroud)
只需确保传递与地点一样多的值.SQLite 中主机参数的默认最大限制是999 - 至少在正常构建中,不确定Android :)
快乐的编码.
这是一个实现:
String makePlaceholders(int len) {
if (len < 1) {
// It will lead to an invalid query anyway ..
throw new RuntimeException("No placeholders");
} else {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
}
Run Code Online (Sandbox Code Playgroud)
简短的例子,基于user166390的回答:
public Cursor selectRowsByCodes(String[] codes) {
try {
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String[] sqlSelect = {COLUMN_NAME_ID, COLUMN_NAME_CODE, COLUMN_NAME_NAME, COLUMN_NAME_PURPOSE, COLUMN_NAME_STATUS};
String sqlTables = "Enumbers";
qb.setTables(sqlTables);
Cursor c = qb.query(db, sqlSelect, COLUMN_NAME_CODE+" IN (" +
TextUtils.join(",", Collections.nCopies(codes.length, "?")) +
")", codes,
null, null, null);
c.moveToFirst();
return c;
} catch (Exception e) {
Log.e(this.getClass().getCanonicalName(), e.getMessage() + e.getStackTrace().toString());
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
可悲的是,没有办法做到这一点(显然'name1', 'name2'
这不是一个单一的值,因此不能在准备好的语句中使用)。
因此,您将不得不放低视线(例如,通过创建非常具体的,不可重用的查询,例如WHERE name IN (?, ?, ?)
)或不使用存储过程,并尝试使用其他一些技术来防止SQL注入...
作为已接受答案的建议,但不使用自定义函数生成逗号分隔的'?'.请检查下面的代码.
String[] names = { "name1", "name2" }; // do whatever is needed first
String query = "SELECT * FROM table"
+ " WHERE name IN (" + TextUtils.join(",", Collections.nCopies(names.length, "?")) + ")";
Cursor cursor = mDb.rawQuery(query, names);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
48142 次 |
最近记录: |