PostgreSQL vs Oracle:PL/pgSQL 的“编译时”检查
Posted
技术标签:
【中文标题】PostgreSQL vs Oracle:PL/pgSQL 的“编译时”检查【英文标题】:PostgreSQL vs Oracle: "compile-time" checking of PL/pgSQL 【发布时间】:2014-10-13 15:39:13 【问题描述】:执行摘要: PostgreSQL 很棒,但我们在工作中面临许多问题,因为它将对 PL/pgSQL 代码的许多检查推迟到运行时。 有没有办法让它在这方面更像 Oracle 的 PL/SQL?
例如...
尝试在任何 Oracle 数据库中执行此操作:
create function foo return number as
begin
select a from dual;
return a;
end;
Oracle 将立即(即在编译时!)响应:
[Error] ORA-00904: invalid identifier
现在试试 PostgreSQL 中语义等价的东西:
CREATE OR REPLACE FUNCTION public.foo ()
RETURNS integer AS
$body$
BEGIN
select a;
return a;
END;
$body$
LANGUAGE plpgsql;
你会看到它 - 不幸的是! - 执行正常...没有报错。
但是当你尝试调用这个函数时(即在运行时)你会得到:
ERROR: column "a" does not exist
LINE 1: select a
有没有办法强制 PostgreSQL 在函数定义时执行语法分析和检查——而不是在运行时?我们有大量遗留的 PL/SQL 代码在工作,我们正在将它们移植到 PostgreSQL - 但是缺少编译时检查非常痛苦,迫使我们进行手动工作 - 即编写代码进行测试所有函数/过程中的所有代码路径 - 否则在 Oracle 中是自动化的。
【问题讨论】:
【参考方案1】:是的,这是一个已知问题。
PL/pgSQL(与任何其他函数一样,SQL
除外)是 PostgreSQL 的“黑匣子”,因此除了运行时之外,实际上不可能检测到错误。
你可以做几件事:
-
将调用
SQL
查询的函数包装到BEGIN
/ COMMIT
语句中,以便更好地控制错误;
将EXCEPTION
blocks 添加到您的代码中以捕获和跟踪错误。但请注意,这会影响函数性能;
使用plpgsql_check
extension,由 Pavel Stěhule 开发,他是 PL/pgSQL 开发的主要贡献者之一。我想这个扩展最终会成为 PostgreSQL 的核心,但这需要一些时间(现在我们处于 9.4beta3 状态);
您还可以查看这个相关问题:postgresql syntax check without running the query
看起来您确实非常需要一个单元测试框架。
【讨论】:
关于测试的问题,我建议原发帖者立即前往pgtap.org,让他的生活更加轻松。【参考方案2】:Plpgsql 语言在编译时没有进行语义检查。我不确定这个特性是旧 plpgsql 实现的意图还是副作用,但随着时间的推移,我们发现了它的一些优点(但也有你提到的缺点)。
加号:
函数和其他数据库对象之间的依赖问题较少。这是循环依赖问题的简单解决方案。 plpgsql函数的部署更容易,因为你不需要尊重依赖。 一些带有临时表的模式可以使用惰性依赖检查。这是必要的,因为 Postgres 不支持全局临时表。例子:
BEGIN
CREATE TEMP TABLE xx(a int);
INSERT INTO xx VALUES(10); -- isn't possible with compile-time dependency checks
END;
减号:
编译时深度检查是不可能的(标识符检查),虽然有时是可能的。对于一些较大的项目,应使用多种解决方案:
回归和单元测试 - 这是基础,因为某些情况无法静态检查 - 例如动态 SQL。plpgsql_check
- 它是一些大公司和更大的 plpgsql 用户使用的外部但受支持的项目。它可以强制对 SQL 标识符的有效性进行静态检查。您可以通过 DDL 触发器强制执行此检查。
【讨论】:
以上是关于PostgreSQL vs Oracle:PL/pgSQL 的“编译时”检查的主要内容,如果未能解决你的问题,请参考以下文章
“王者对战”之 MySQL 8 vs PostgreSQL 10