gpt4 book ai didi

android - SQLite rawQuery selectionArgs 和整数字段

转载 作者:IT王子 更新时间:2023-10-29 06:21:42 27 4
gpt4 key购买 nike

正如Android文档所说,rawQuery方法的selectionArgs参数被解析为字符串。

SQLiteDatabase.rawQuery(String sql, String[] selectionArgs)

selectionArgs: You may include ?s in where clause in the query,which will be replaced by the values from selectionArgs.The values will be bound as Strings.

但是今天,我遇到了一个问题,这个问题占用了我一天的大部分时间。想象一下以下查询:

SELECT * FROM TABLE_A WHERE IFNULL(COLUMN_A, 0) >= 15

COLUMN_A 是整数。该表有大约 10 行符合该标准。在数据库编辑器上运行查询,结果总是正确的,但在智能手机上,语句总是没有返回任何行。

一段时间后,A 将查询更改为:

SELECT * FROM TABLE_A WHERE IFNULL(COLUMN_A, 0) >= '15'

并且编辑器没有返回任何行,就像 Android 一样。因此,将查询更改为:

SELECT * FROM TABLE_A WHERE CAST(IFNULL(COLUMN_A, 0) as INTEGER) >= '15'

解决了这个问题。完成的另一个测试是:

SELECT * FROM TABLE_A WHERE COLUMN_A >= '15'

同样,返回了正确的结果。

这似乎是一个问题,涉及 Android 使用 IFNULL 子句将参数绑定(bind)到查询(作为字符串)的方式。

所以,有人知道为什么会这样吗?是否有任何建议可以在不对查询使用 CAST 的情况下解决此问题?

最佳答案

将您的值绑定(bind)到查询的原因是为了防止 SQL-injection attack .

基本上,您将查询(包括占位符)发送到您的数据库并说“我的下一个查询将采用这种形式,而不是其他形式!”。当攻击者随后注入(inject)不同的查询字符串(例如,通过表单字段)时,数据库会说“嘿,这不是你说要发送的查询!”并向您抛出错误。

Since commands (which can be injected into your actual query as show in the linked article) are strings, the string-datatype is the more "dangerous" one. If a user tries to inject some code into your field which should only take numbers and you try to cast/parse the input to an integer (before putting the value into your query), you'll get an exception right away. With a string, there is no such kind security. Therefor, they have to be escaped probably. That might be the reason that the bind values are all interpreted as strings.

以上是伪造的!您绑定(bind)的参数是字符串还是整数并不重要,它们都同样危险。此外,在代码中预先检查您的值会产生大量样板代码,容易出错且不灵活!


为了防止您的应用程序遭受 SQL 注入(inject)并加速多个数据库写入 操作(使用具有不同值的相同查询),您应该使用“准备好的语句”。在 Android SDK 中写入数据库的正确类是 SQLiteStatement .

要创建准备好的语句,您可以使用 compileStatement()-method您的 SQLiteDatabase-object 并使用正确的 bindXX()-方法(继承自 SQLiteProgram ):

SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("INSERT INTO SomeTable (name, age) values (?,?)");
// Careful! The index begins at 1, not 0 !!
stmt.bindString(1, "Jon");
stmt.bindLong(2, 48L);
stmt.execute();
// Also important! Clean up after yourself.
stmt.close();

示例取自这个较旧的问题:How do I use prepared statements in SQlite in Android?


遗憾的是,SQLiteStatement 没有返回Cursor 的重载,因此您不能将它用于SELECT 语句。对于那些,您可以使用 rawQuery(String, String[])-SQLiteDatabase 的方法:

int number = getNumberFromUser();
String[] arguments = new String[]{String.valueOf(number)};
db.rawQuery("SELECT * FROM TABLE_A WHERE IFNULL(COLUMN_A, 0) >= ?", arguments);

请注意,rawQuery() 方法采用字符串数组作为参数值。这其实没关系,SQLite 会自动转换为正确的类型。只要字符串表示形式与您在 SQL 查询中所期望的相同,就没问题。

关于android - SQLite rawQuery selectionArgs 和整数字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11320434/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com