Best way to pass the schema name as a variable to a query

一笑奈何 提交于 2019-12-11 06:53:19

问题


I have a PlayFramework server (with Anorm) which operates against a database with several schemas, all of them with the same tables.

Most of my "access to database" functions look like:

def findById(zoneName: String, id: Long): Option[Employee] = {
    DB.withConnection { implicit connection =>
      SQL("""select *
          from """+zoneName+"""employee
          where employee._id = {id}"""
      .on(
          '_id -> id
        ).as(simpleParser.singleOpt)
    }
  }

But I know this is a wrong approach, because it is not SQL-Injection-safe and of course it is tedious to write in every function.

I want to use String interpolation to correct this, it works well with my id variable, but it doesn't with zoneName:

def findById(zoneName: String, id: Long): Option[Employee] = {
    DB.withConnection { implicit connection =>
      SQL"""select *
          from $zoneName.employee
          where employee._id = 1"""
      .as(simpleParser.singleOpt)
    }
  }

Gives me:

info] ! @6lenhal6c - Internal server error, for (GET) [/limbo/br/employee/1] ->
[info] 
[info] play.api.Application$$anon$1: Execution exception[[PSQLException: ERROR: syntax error at or near «$1»
[info]   Position: 25]]
[info]  at play.api.Application$class.handleError(Application.scala:296) ~[play_2.11-2.3.8.jar:2.3.8]
[info]  at play.api.DefaultApplication.handleError(Application.scala:402) [play_2.11-2.3.8.jar:2.3.8]
[info]  at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.8.jar:2.3.8]
[info]  at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [play_2.11-2.3.8.jar:2.3.8]
[info]  at scala.Option.map(Option.scala:146) [scala-library-2.11.5.jar:na]
[info] Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near «$1»
[info]   Position: 25
[info]  at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198) ~[postgresql-9.3-1102.jdbc4.jar:na]
[info]  at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927) ~[postgresql-9.3-1102.jdbc4.jar:na]
[info]  at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255) ~[postgresql-9.3-1102.jdbc4.jar:na]
[info]  at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561) ~[postgresql-9.3-1102.jdbc4.jar:na

Tested also with ${zoneName} with the same result.

Any help or advice about how to write this would be appreciated, thank you in advance!


回答1:


Using Anorm String interpolation, any $expression is to be provided a parameter, that is to say if it's a string it will quoted by the JDBC driver.

If you want to substitute part of the SQL statement with string (e.g. dynamic schema), either you can use concatenation, or since latest versions (2.4.0-M3 or 2.3.8) the syntax #$expr.

val table = "myTable"
SQL"SELECT * FROM #$table WHERE id=$id"
// SELECT * FROM myTable WHERE id=?


来源:https://stackoverflow.com/questions/29028122/best-way-to-pass-the-schema-name-as-a-variable-to-a-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!