PostgreSQL 14破解了PostgreSQL的.NET和Java驱动
在某些情况下,PostgreSQL 14中的新语法会破坏其官方的.NET和Java数据库驱动。具体来说,当使用这两种方法来创建一个使用BEGIN ATOMIC ... 的SQL函数时。结束。如果你没有通过Npgsql或PgJDBC修改你的数据库模式,就不必担心。
Java的JDBC和.NET的ADO.NET数据库驱动框架有一个共同的特点:它们都支持使用分号来批处理SQL语句。这被认为是出于性能方面的考虑,是必要的。如果你一次发送一条命令,你必须为每条命令支付延迟成本。相反,通过发送一个批次,你只需要支付一次成本。
对于一些数据库,比如SQL Server,你可以把整个批处理作为一个巨大的SQL字符串来发送。但是PostgreSQL的线格式并不是这样的。客户端需要把批处理分成单独的命令,尽管它们仍然作为一个集合被发送。
天真的实现方式是简单地认为每个分号意味着该批处理的结束。当然,有可能分号并不代表语句的结束,而只是一个字符串字面的一部分。Npgsql和PgJDBC解析器考虑到了这一点。
到目前为止还不错。但是,如果你要定义一个由多个语句组成的新的SQL函数,该怎么办?这仍然不是一个问题,因为函数的主体将使用美元引号来转义。在$$符号对内的任何分号都会被当作其他的字符串字面处理。
然后,PostgreSQL 14出现了,增加了BEGIN ATOMIC ...END,也被称为 "SQL标准语法",发布说明中说:
当用SQL标准语法编写一个函数或过程时,主体会被立即解析并存储为解析树。这允许更好地跟踪函数的依赖性,并能带来安全方面的好处。
由于分号可以出现在BEGIN ATOMIC ...由于分号可以出现在BEGIN ATOMIC ... END块内的任何地方,而不是在一个带引号的字符串中,所以解析器不能使用当前的方法来确定批处理应该被划分为哪些语句。完全支持这一点需要改变API或者建立一个新的、复杂得多的分析器。
由于他们已经关注到当前解析器造成的开销,Npgsql决定改变API。他们在库中加入了他们所谓的原始SQL模式。这种模式也需要使用位置参数而不是命名参数。
PgJDBC团队还没有决定采取哪种方式。你可以在题为New PG14 SQL-standard function bodies break our SQL parser的错误报告中跟踪他们的进展。