异常字符串插值不替换变量
Anorm String Interpolation not replacing variables
我们正在使用 Scala Play,我正在努力确保所有 SQL 查询都在使用 Anorm 的字符串插值。它适用于某些查询,但许多查询实际上并没有在执行查询之前替换变量。
import anorm.SQL
import anorm.SqlStringInterpolation
object SecureFile
{
val table = "secure_file"
val pk = "secure_file_idx"
...
// This method works exactly as I would hope
def insert(secureFile: SecureFile): Option[Long] = {
DBExec { implicit connection =>
SQL"""
INSERT INTO secure_file (
subscriber_idx,
mime_type,
file_size_bytes,
portal_msg_idx
) VALUES (
${secureFile.subscriberIdx},
${secureFile.mimeType},
${secureFile.fileSizeBytes},
${secureFile.portalMsgIdx}
)
""" executeInsert()
}
}
def delete(secureFileIdx: Long): Int = {
DBExec { implicit connection =>
// Prints correct values
println(s"table: ${table} pk: ${pk} secureFileIdx: ${secureFileIdx} ")
// Does not work
SQL"""
DELETE FROM $table WHERE ${pk} = ${secureFileIdx}
""".executeUpdate()
// Works, but unsafe
val query = s"DELETE FROM ${table} WHERE ${pk} = ${secureFileIdx}"
SQL(query).executeUpdate()
}
}
....
}
在 PostgreSQL 日志中,很明显 delete 语句没有获取正确的值:
2015-01-09 17:23:03 MST ERROR: syntax error at or near "" at character 23
2015-01-09 17:23:03 MST STATEMENT: DELETE FROM WHERE =
2015-01-09 17:23:03 MST LOG: execute S_1: ROLLBACK
我已经尝试了 execute、executeUpdate 和 executeQuery 的许多变体,结果相似。目前,我们正在使用基本的字符串替换,但这当然很糟糕,因为它没有使用 PreparedStatements。
Anorm 字符串插值被引入以传递参数(例如 SQL"Select * From Test Where id = $x
),插值参数(例如 $x
)根据适当的类型转换在基础 PreparedStament
上设置(参见上的用例https://www.playframework.com/documentation/2.3.x/ScalaAnorm).
下一个 Anorm 版本也将有 #$foo
语法来混合参数插值和标准字符串插值。这将允许编写 DELETE FROM #$table WHERE #${pk} = ${secureFileIdx}
并将其作为 DELETE FROM foo WHERE bar = ?
执行(如果文字 table
是 "foo"
并且 pk
是 "bar"
),使用文字secureFileIdx
作为参数传递。见相关 pull request.
在发布下一个修订版之前,您可以从其主源构建 Anorm,并从中受益。
对于坐在这个页面上挠头并想知道他们可能遗漏了什么的其他人......
SQL("select * from mytable where id = $id")
与
不同
SQL"select * from mytable where id = $id"
前者不做字符串插值,后者做。
这在上述文档中很容易被忽视,因为提供的所有样本恰好有一个(不相关的)右括号(就像这句话一样)
我们正在使用 Scala Play,我正在努力确保所有 SQL 查询都在使用 Anorm 的字符串插值。它适用于某些查询,但许多查询实际上并没有在执行查询之前替换变量。
import anorm.SQL
import anorm.SqlStringInterpolation
object SecureFile
{
val table = "secure_file"
val pk = "secure_file_idx"
...
// This method works exactly as I would hope
def insert(secureFile: SecureFile): Option[Long] = {
DBExec { implicit connection =>
SQL"""
INSERT INTO secure_file (
subscriber_idx,
mime_type,
file_size_bytes,
portal_msg_idx
) VALUES (
${secureFile.subscriberIdx},
${secureFile.mimeType},
${secureFile.fileSizeBytes},
${secureFile.portalMsgIdx}
)
""" executeInsert()
}
}
def delete(secureFileIdx: Long): Int = {
DBExec { implicit connection =>
// Prints correct values
println(s"table: ${table} pk: ${pk} secureFileIdx: ${secureFileIdx} ")
// Does not work
SQL"""
DELETE FROM $table WHERE ${pk} = ${secureFileIdx}
""".executeUpdate()
// Works, but unsafe
val query = s"DELETE FROM ${table} WHERE ${pk} = ${secureFileIdx}"
SQL(query).executeUpdate()
}
}
....
}
在 PostgreSQL 日志中,很明显 delete 语句没有获取正确的值:
2015-01-09 17:23:03 MST ERROR: syntax error at or near "" at character 23
2015-01-09 17:23:03 MST STATEMENT: DELETE FROM WHERE =
2015-01-09 17:23:03 MST LOG: execute S_1: ROLLBACK
我已经尝试了 execute、executeUpdate 和 executeQuery 的许多变体,结果相似。目前,我们正在使用基本的字符串替换,但这当然很糟糕,因为它没有使用 PreparedStatements。
Anorm 字符串插值被引入以传递参数(例如 SQL"Select * From Test Where id = $x
),插值参数(例如 $x
)根据适当的类型转换在基础 PreparedStament
上设置(参见上的用例https://www.playframework.com/documentation/2.3.x/ScalaAnorm).
下一个 Anorm 版本也将有 #$foo
语法来混合参数插值和标准字符串插值。这将允许编写 DELETE FROM #$table WHERE #${pk} = ${secureFileIdx}
并将其作为 DELETE FROM foo WHERE bar = ?
执行(如果文字 table
是 "foo"
并且 pk
是 "bar"
),使用文字secureFileIdx
作为参数传递。见相关 pull request.
在发布下一个修订版之前,您可以从其主源构建 Anorm,并从中受益。
对于坐在这个页面上挠头并想知道他们可能遗漏了什么的其他人......
SQL("select * from mytable where id = $id")
与
不同SQL"select * from mytable where id = $id"
前者不做字符串插值,后者做。
这在上述文档中很容易被忽视,因为提供的所有样本恰好有一个(不相关的)右括号(就像这句话一样)