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 的“编译时”检查的主要内容,如果未能解决你的问题,请参考以下文章

SQLite vs MySQL vs PostgreSQL

“王者对战”之 MySQL 8 vs PostgreSQL 10

Postgresql 多数据库 VS 多模式

如何在VS2015中使用PostgreSQL插件静态编译Qt 5.8

阿里云DTS VS MySQLdump

[转帖] “王者对战”之 MySQL 8 vs PostgreSQL 10