PostgreSQL与Oracle:"编译时"检查PL / pgSQL

时间:2014-10-13 15:39:14

标签: oracle postgresql plsql plpgsql

执行摘要: 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中都是自动化的。

2 个答案:

答案 0 :(得分:7)

是的,这是一个已知问题。

PL / pgSQL(与SQL除外的任何其他函数一样)是PostgreSQL的“黑盒子”,因此除了在运行时之外不可能检测到错误。

你可以做几件事:

  1. 将调用SQLBEGIN个查询的函数包装到COMMIT / {{1}}语句中,以便更好地控制错误;
  2. EXCEPTION blocks添加到您的代码中以捕获和跟踪错误。但请注意,这会影响功能性能;
  3. 使用由PavelStěhule开发的plpgsql_check extension,他是PL / pgSQL开发的主要贡献者之一。我想最终这个扩展会使它成为PostgreSQL的核心,但它需要一些时间(现在我们处于9.4beta3状态);
  4. 您还可以查看以下相关问题:postgresql syntax check without running the query
  5. 看起来你真的需要一个单元测试框架。

答案 1 :(得分:4)

Plpgsql语言的设计在编译时没有语义检查。我不确定这个功能如何是旧的plpgsql实现的意图或副作用,但是我们发现了一些优点(但是你提到的缺点)。

加:

  • 函数与其他数据库对象之间的依赖关系较少。它是循环依赖的简单解决方案。部署plpgsql函数更简单,因为您不需要尊重依赖。
  • 由于延迟依赖性,某些具有临时表的模式是可能的。这是必要的,因为Postgres不支持全局临时表。

示例:

BEGIN
  CREATE TEMP TABLE xx(a int);
  INSERT INTO xx VALUES(10); -- isn't possible with compile time dependency
END;

减:

  • 虽然有时可能会进行深度检查(标识符检查),但是没有可能。

对于一些较大的项目,应该使用各种解决方案:

  • 回归和单元测试 - 它是基础的,因为某些情况不能静态检查 - 例如动态SQL。
  • plpgsql_check - 它是外部的,但支持的项目使用了一些更大的公司和更大的plpgsql用户。它可以强制执行SQL标识符有效性的静态检查。您可以通过DDL触发器强制执行此检查。