执行摘要: PostgreSQL很棒,但由于它推迟了很多PL / pgSQL代码检查直到运行时间,因此我们面临着许多工作中的问题。 有没有办法让它在这方面更像是Oracle的PL / SQL ?
例如......
尝试在任何Oracle DB中执行此操作:
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中都是自动化的。
答案 0 :(得分:7)
是的,这是一个已知问题。
PL / pgSQL(与SQL
除外的任何其他函数一样)是PostgreSQL的“黑盒子”,因此除了在运行时之外不可能检测到错误。
你可以做几件事:
SQL
个BEGIN
个查询的函数包装到COMMIT
/ {{1}}语句中,以便更好地控制错误; EXCEPTION
blocks添加到您的代码中以捕获和跟踪错误。但请注意,这会影响功能性能; plpgsql_check
extension,他是PL / pgSQL开发的主要贡献者之一。我想最终这个扩展会使它成为PostgreSQL的核心,但它需要一些时间(现在我们处于9.4beta3状态); 看起来你真的需要一个单元测试框架。
答案 1 :(得分:4)
Plpgsql语言的设计在编译时没有语义检查。我不确定这个功能如何是旧的plpgsql实现的意图或副作用,但是我们发现了一些优点(但是你提到的缺点)。
加:
示例:
BEGIN
CREATE TEMP TABLE xx(a int);
INSERT INTO xx VALUES(10); -- isn't possible with compile time dependency
END;
减:
对于一些较大的项目,应该使用各种解决方案:
plpgsql_check
- 它是外部的,但支持的项目使用了一些更大的公司和更大的plpgsql用户。它可以强制执行SQL标识符有效性的静态检查。您可以通过DDL触发器强制执行此检查。