SBT 为 PostgreSQL 查询抛出 JdbcSQLExceptionSyntax 异常

SBT throwing JdbcSQLExceptionSyntax exception for an PostgreSQL query

我是 运行 一个 SQL 查询,使用 slick 写入 PostgreSQL 数据库。为什么我在 SQL 语句错误中收到语法错误?请假设所有配置都是正确的。

我在客户端中导入了 import slick.jdbc.PostgresProfile.api._,在查询生成器中导入了 import slick.jdbc.H2Profile.api._。我还将 postgresql 和 MySQL 语句分离到不同的构建器中。

import bbc.rms.client.programmes.util.MySqlStringEscaper
import org.joda.time.DateTime
import slick.jdbc.H2Profile.api._

abstract class PopularBlurProgrammesQueryBuilder extends QueryBuilder with                 
MySqlStringEscaper {

  def incrementBlurScoreQuery(pid: String, date: DateTime): DBIO[Int] = {
    sqlu"""
          INSERT INTO radio.core_entity_popularity (pid, score, date)
          VALUES($pid, 1, ${flooredSQLDateTimeString(date)}
          ) ON CONFLICT ON CONSTRAINT core_entity_popularity_pkey
          DO UPDATE
          SET score = core_entity_popularity.score + 1
    """
  }
}

````

import slick.jdbc.PostgresProfile.api._

class SlickPopularBlurProgrammesClient[T](database: Database)(implicit 
executionContext: ExecutionContext)
  extends PopularBlurProgrammesQueryBuilder with 
PopularBlurProgrammesClient[T] {

override def writeBlurIncrementedScore(pid: String, date: DateTime): 
 Future[Int] = {
   database.run(incrementBlurScoreQuery(pid, date))
  }
}

预期结果是没有抛出异常,集成测试通过。集成测试:

val currentDate = dateTimeFormat.parseDateTime("2018-12-19 16:00:00")
client.writeBlurIncrementedScore("pid", currentDate)
whenReady(client.writeBlurIncrementedScore("pid", currentDate)) { 
updatedRows =>
    updatedRows must be equalTo 1
  }
}

堆栈跟踪:

    org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "
      INSERT INTO radio.core_entity_popularity (pid, score, date)
      VALUES(?, 1, ?
      ) ON[*] CONFLICT ON CONSTRAINT core_entity_popularity_pkey
      DO UPDATE
      SET score = core_entity_popularity.score + 1
    "; SQL statement:

      INSERT INTO radio.core_entity_popularity (pid, score, date)
      VALUES(?, 1, ?
      ) ON CONFLICT ON CONSTRAINT core_entity_popularity_pkey
      DO UPDATE
      SET score = core_entity_popularity.score + 1
 [42000-193]
org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "
      INSERT INTO radio.core_entity_popularity (pid, score, date)
      VALUES(?, 1, ?
      ) ON[*] CONFLICT ON CONSTRAINT core_entity_popularity_pkey
      DO UPDATE
      SET score = core_entity_popularity.score + 1
"; SQL statement:

      INSERT INTO radio.core_entity_popularity (pid, score, date)
      VALUES(?, 1, ?
      ) ON CONFLICT ON CONSTRAINT core_entity_popularity_pkey
      DO UPDATE
      SET score = core_entity_popularity.score + 1
 [42000-193]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.message.DbException.getSyntaxError(DbException.java:191)
at org.h2.command.Parser.getSyntaxError(Parser.java:530)
at org.h2.command.Parser.prepareCommand(Parser.java:257)
at org.h2.engine.Session.prepareLocal(Session.java:561)
at org.h2.engine.Session.prepareCommand(Session.java:502)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1203)
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:73)
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:287)
at slick.jdbc.JdbcBackend$SessionDef$class.prepareStatement(JdbcBackend.scala:336)
at slick.jdbc.JdbcBackend$BaseSession.prepareStatement(JdbcBackend.scala:448)
at slick.jdbc.StatementInvoker.results(StatementInvoker.scala:32)
at slick.jdbc.StatementInvoker.iteratorTo(StatementInvoker.scala:21)
at slick.jdbc.Invoker$class.first(Invoker.scala:30)
at slick.jdbc.StatementInvoker.first(StatementInvoker.scala:15)
at slick.jdbc.StreamingInvokerAction$HeadAction.run(StreamingInvokerAction.scala:52)
at slick.jdbc.StreamingInvokerAction$HeadAction.run(StreamingInvokerAction.scala:51)
at slick.basic.BasicBackend$DatabaseDef$$anon.liftedTree1(BasicBackend.scala:275)
at slick.basic.BasicBackend$DatabaseDef$$anon.run(BasicBackend.scala:275)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

您面临的问题是您正在向 H2 数据库提交特定的 PostgreSQL 查询。

PostgreSQL 的 INSERT 语法允许键 ON CONFLICT

[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
     { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
     [ ON CONFLICT [ conflict_target ] conflict_action ]
     [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

where conflict_target can be one of:

     ( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
     ON CONSTRAINT constraint_name

and conflict_action is one of:

     DO NOTHING
     DO UPDATE SET { column_name = { expression | DEFAULT } |
                ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) |
                ( column_name [, ...] ) = ( sub-SELECT )
              } [, ...]
          [ WHERE condition ]

来自 PostgreSQL docs

而 H2 INSERT 语法是

INSERT INTO tableName 
{ [ ( columnName [,...] ) ] 
{ VALUES 
{ ( { DEFAULT | expression } [,...] ) } [,...] | [ DIRECT ] [ SORTED ] select } } | 
{ SET { columnName = { DEFAULT | expression } } [,...] }

来自 H2 DB docs

问题是 postgreSQL 对表达式非常严格,不喜欢处理日期的方式。它没有明确知道日期值是否是时间戳,所以我不得不明确调用 postgreSQL 函数 to_timestamp(text, text) 并添加 $ 以在查询中使用变量。