PostgreSQL vs Oracle:PL/pgSQL 的"compile-time"检查



执行摘要: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的"黑匣子",因此除了在运行时之外,不可能真正检测到错误。

你可以做几件事:

  1. 将调用SQL查询的函数包装成BEGIN/COMMIT语句,以便更好地控制错误
  2. EXCEPTION块添加到代码中以捕获和跟踪错误。不过,请注意,这将影响功能性能
  3. 使用plpgsql_check扩展,由Pavel StŞhule开发,他是PL/pgSQL开发的主要贡献者之一。我想这个扩展最终会使它成为PostgreSQL的核心,但这需要一些时间(现在我们处于9.4beta3状态)
  4. 您还可以研究这个相关的问题:在不运行查询的情况下进行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触发器强制执行此检查

相关内容

最新更新