我通过AJAX为搜索栏供电,该搜索栏传递与数据库列相关的选定过滤器(单选按钮)和搜索栏中输入的任何内容的搜索字符串。我正在使用的scala / play / anorm代码是:
def searchDB(searchString: String, filter: String): List[DatabaseResult] = {
DB.withConnection { implicit c =>
SQL(
"""
SELECT name, email, emailsecondary, picture, linkedin, title, company, companylink, companydesc, location, github, stackoverflow, twitter, blog
FROM mailinglistperson
WHERE {filter} LIKE '%{searchString}%'
""").on(
'filter -> filter,
'searchString -> searchString
).as(databaseResultParser.*)
}
}
当我使用与上述anorm代码同构的psql
对数据库(PostgreSQL)运行查询时,它会返回2个结果,即:
select id, name, email from mailinglistperson where company like '%kixer%';
但是当传递完全相同的值时,anorm代码会返回0结果(我已通过println' s验证了这些值)
编辑:当我切换anorm代码以使用String Interpolation时,我得到:
[error] - play.core.server.netty.PlayDefaultUpstreamHandler - Cannot invoke the action
java.lang.RuntimeException: No parameter value for placeholder: 3
EDIT2:我也试过传递'%...%'与searchString一起进入LIKE并且仍然得到0结果。
答案 0 :(得分:1)
有两个问题 - 列的名称和过滤器值
对于过滤器值:您必须省略SQL命令中的单个刻度,并且您应该在参数中传递占位符“%”。如果是字符串,则会自动处理刻度。
至于列名:它就像一个字符串参数,所以再次滴答也会自动处理:
[debug] c.j.b.PreparedStatementHandle - select ... from ... where'filter'like'%aaa%'
一种解决方案:使用普通字符串插值s"""... $filter ..."""
。
所有在一起:
SQL(
s"""
SELECT name, email, ...
FROM mailinglistperson
WHERE $filter LIKE {searchString}
""").on(
'searchString -> "%" + searchString + "%"
).as(databaseResultParser.*)
但是之前应该进行检查,例如
val validColumns = List("name", "email")
if (validColumns.contains(filter)) == false) {
throw new IllegalArgumentException("...")
}
防止SQL注入。
<强>更新强>
正如cchantep所指出的:如果使用Anorm&gt; = 2.4 ,可以使用混合插值(列名和值):
SQL"... WHERE #$filter LIKE $searchString"
在这种情况下,它对SQL注入是部分安全的:仅覆盖值,而不列名。
更新2
关于记录SQL语句,请参阅Where to see the logged sql statements in play2?
但是当你使用PostgreSQL时我建议明确的来源:PostgreSQL日志:postgresql.conf
:
log_statement ='all'#none,ddl,mod,all
然后您将在PostgreSQL日志文件中看到类似这样的内容:
日志:从test50中选择*,其中名称为$ 1
详细信息:参数:$ 1 ='%aaa'