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 ]
而 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)
并添加 $
以在查询中使用变量。
我是 运行 一个 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 ]
而 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)
并添加 $
以在查询中使用变量。