执行摘要: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中是自动化的。
是的,这是一个已知的问题。
PL/pgSQL(和任何其他函数一样,除了SQL
上的函数)是PostgreSQL的"黑匣子",因此除了在运行时之外,不可能真正检测到错误。
你可以做几件事:
- 将调用
SQL
查询的函数包装成BEGIN
/COMMIT
语句,以便更好地控制错误 - 将
EXCEPTION
块添加到代码中以捕获和跟踪错误。不过,请注意,这将影响功能性能 - 使用
plpgsql_check
扩展,由Pavel StŞhule开发,他是PL/pgSQL开发的主要贡献者之一。我想这个扩展最终会使它成为PostgreSQL的核心,但这需要一些时间(现在我们处于9.4beta3状态) - 您还可以研究这个相关的问题:在不运行查询的情况下进行postgresql语法检查
看起来你确实非常需要一个单元测试框架。
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触发器强制执行此检查