快速而又脏的SQL字符串转义

时间:2011-08-10 06:13:33

标签: java sql postgresql escaping

我正在为一个带有postgresql DB的Web应用程序的home QueryBuilder类进行最后润色。它对所有查询使用PreparedStatement,并且不受SQL注入的影响。

但是,我想要一种“快速而肮脏”的方式来表示QueryBuilder及其toString()方法,仅用于调试目的。该方法将按正常传递到PreparedStatement的方式汇编查询字符串,然后简单地将字符串中的每个?替换为其相应的单引号值。 toString() javadoc将警告其他开发人员,这是一种不安全的近似,仅用于调试等等。

我知道这些值的单引号应该加倍(即O'Connell转义为O''Connell)。是否还有其他应该处理的特殊字符我忘记了?我找了类似的问题,但只发现有人被骂使用PreparedStatement(他们应该这样做,让记录显示)。

编辑:不希望使用第三方工具执行此特定任务,我真的只想在这里快速而肮脏。我确实很欣赏这些链接 - 我可能会将它们视为其他用途。

最后编辑:感谢所有有用的指针。我只是想为那些从谷歌偶然发现的人添加它, not 使用这些技巧来处理数据库,使用PreparedStatement

3 个答案:

答案 0 :(得分:5)

对于“快速而肮脏”的逃避,将撇号加倍是足够好的。但请注意字符串文字中已有的问号:

SELECT column FROM table WHERE column = 'A question?' or column = ?

您不想替换第一个问号。此外,应该注意这些角落:

SELECT /* Is this a comment?? */ * FROM table
-- -- --  Another comment??
WHERE column = ?

该语句中只有一个绑定值。对于一个不那么快速和肮脏的解决方案,您可以使用像jOOQ这样的库来解决这个问题(免责声明:我为jOOQ背后的公司工作)。它会为你做内联,也适用于更讨厌的数据类型:

DSLContext ctx = DSL.using(SQLDialect.POSTGRES);
Object[] bindValues = { 1, "a'bc", Date.valueOf("2012-09-24"), "xy".getBytes() };
String string = ctx.query(
  "SELECT 1 WHERE A = ? AND B = ? AND C = ? AND D = ?",
  bindValues).toString();

以上将呈现

SELECT 1 
WHERE A = 1 
AND B = 'a''bc'
AND C = date '2012-09-24' 
AND D = E'\\170\\171::bytea

答案 1 :(得分:2)

如果您不反对使用第三方开源库,那么我想看看Apache Commons Lang的StringEscapeUtils.escapeSql(String str)

编辑:我刚检查了source。它只会用两个单引号(')替换单引号('')。

答案 2 :(得分:1)

也许您可以查看来自Apache StringEscapeUtilsescapeJava(String input)

  

public static final String escapeJava(String input)

     

使用Java String规则转义字符串中的字符。