Best way to pass the schema name as a variable to

2019-08-12 22:18发布

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条回答
祖国的老花朵
2楼-- · 2019-08-12 23:07

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=?
查看更多
登录 后发表回答