如何在安卓上避免SQLite不支持的字符?

19

请问有人能告诉我如何在 Android 中的 SQLite 数据库中转义或替换不支持的字符,比如单引号吗?可以举个例子吗?

谢谢!

3个回答

41
你可以使用commons-lang实用程序或者使用正则表达式来处理它。
如果你正在构建动态SQL,我建议尝试使用预编译语句来消除转义单引号的需要。
只使用字符串拼接构建动态SQL:
String value = "one's self";
StringBuilder query= new StringBuilder();
query.append("insert into tname(foo) values (").append(value).append(")");
... execute call with query.toString() ...

将其更改为

String value = "one's self";
value= DatabaseUtils.sqlEscapeString(value);
StringBuilder query= new StringBuilder();
query.append("insert into tname(foo) values (").append(value).append(")");
... execute call with query.toString() ...

最好使用预处理语句

String value = "one's self";
StringBuilder query= StringBuilder();
query.append("insert into tname(foo) values (?)");
SQLiteStatement stmt= db.compileStatement(query.toString());
stmt.bindString(1, value);
long rowId= stmt.executeInsert();
// do logic check for > -1 on success

这样做可以防止"SQL注入攻击"。

请参考http://developer.android.com/reference/android/database/sqlite/SQLiteStatement.html了解更多信息。

编辑: 我进行了更深入的研究,你可以使用DatabaseUtils.sqlEscapeString(String)来转义字符串内容,以便它适用于一个完整的SQL语句而不需要准备工作。


2
@mohan 确定看一下我上面发布的答案,尤其是 DatabaseUtils.sqlEscapeString(String) 方法。这将"净化"您的输入,使您可以将该值连接到字符串中。我将编辑我的答案以覆盖动态值。 - Dave G
2
目前最佳答案是使用DatabaseUtils.sqlEscapeString()方法,它会为您处理一切。但请记住,它还会在字符串前后添加单引号“'”,因此如果您手动构造查询,请务必将其删除,因为该方法也会添加它们,这将导致您的查询无效。 感谢@DaveG提供的解决方案! - Ionut Negru
DatabaseUtils.sqlEscapeString() - 确实是迄今为止最好的方法 - Richard Le Mesurier
DatabaseUtils.sqlEscapeString() 可以在任何地方使用吗?例如,如果我需要对表名或列类型进行清理,是否可以使用它? - Michael
@Michael 我正在努力理解你的问题 - 这个工具将接受一个字符串,你可能会将其连接起来以创建一个 SQL 值。我不知道它是否适用于你所问的特定用例。 - Dave G
显示剩余2条评论

0

实际上,最简单的方法是用两个单引号('')替换单引号(')。你的查询将变成:

insert into tname(foo) values ('one''s self');

解释: SQLite 倡导使用单引号(')作为字符串定界符,而不是双引号("),称这是 SQL 标准所要求的(我无法确认这一点)。SQLite 还与我知道的所有其他 SQL 数据库不同,它使用''而不是\ ',同样声称符合 SQL 标准。(同样,我无法确认此声明)。

就个人而言,我倾向于不同意这种说法,因为我知道的每个其他 SQL 数据库都使用 C 转义字符的方法,反斜杠。即使某个地方在 ISO 的 SQL 标准中用 '' 来表示转义,我认为最好修改该标准以使用 C 方式,因为在实践中,它已经成为了标准。

请注意:

insert into tname(foo) values ('ones "self"');

根据这个逻辑,这是一个有效的SQL语句,不需要额外的转义。


SQL-92标准规定单引号字符串为<字符字符串字面量>,双引号字符串为<标识符>。如果您跟踪规范,它并没有说明<标识符>可以用作<字符字符串字面量>。事实上,MSSQL不接受需要字符字符串字面量的双引号字符串。例如,SELECT * FROM CUSTOMER WHERE Name = "PapaSloth"; 将在MSSQL中导致错误。 - PapaSloth

0

这些不是用简单的 \ 完成的吗?所以,你的单引号应该是 \'。


1
如果用户要连接字符串,他们需要将 ' 变成 '',因此如果它是 "insert into table (foo) values ('one's self')",则需要更改为 "insert into table (foo) values ('one''s self')"。 - Dave G
没问题,但我不明白为什么要给我点踩。我是真心的。 - Bill Mote
2
您提供的转义字符在SQL中无效,不能解决问题。 - Dave G
1
SQLite不支持C风格的反斜杠\转义,而是使用Pascal风格的' -> ''转义。 - Tuncay Göncüoğlu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接