PL/pgSQL 条件表达式的解析和计算

John Doe 十二月 26, 2024

摘要:在本文中,我们将学习在 PostgreSQL 中 PL/pgSQL 条件表达式是如何解析和计算的。

目录

介绍

最近,在 PostgreSQL 社区中,一位用户发布了一块 PL/pgSQL 代码(如下所示),惊讶地发现它没有产生语法错误:

DO $$
DECLARE i INT;
BEGIN
  i = 0;
  IF i = 0 AND THEN
    RAISE NOTICE 'i = 0';
  END IF;
END; $$;

乍一看,这个代码块似乎并不完整。请注意IF条件:它在AND运算符后面似乎缺少了一个额外的条件。从逻辑上讲,这应该会出现异常,因为AND后面的条件不完整。

  IF i = 0 AND THEN 

但是,在 PL/pgSQL 执行期间,条件被评估,并没有出现任何语法错误或警告。这就提出了一个关键问题:

  • PostgreSQL 在内部如何处理这个条件?
  • 是什么让这个看似不完整的表达式正常工作的呢?
  • 条件 “i = 0 AND” 是如何被处理的?

在检视此类 PL/pgSQL 代码时,它看起来不完整,假设它应该失败的情况下,会令人惊讶。

在本文中,我们将深入研究 PL/pgSQL 的内部结构,以了解此条件语句的处理方式,以及为什么 PostgreSQL 没有将其标记为错误。

PL/pgSQL 内部的代码实现

开源软件的一个最大优势是,能够直接检查代码库。这为我们理解事物的运作方式,或在某些情况下为什么它们没有按预期中断,提供了基础。

我们的调查从PLPGSQL_STMT_IF结构开始,通过在pl_exec.c文件中的调用栈进行跟踪。

通过浏览代码,我们发现IF语句及其条件是使用exec_run_select进行求值的,它有效地执行了一条返回一个布尔结果的SELECT语句。

作为 SELECT 子句的 PL/pgSQL 条件

回顾原始的示例,条件i = 0 AND是在一个SELECT子句中处理的。在这里,AND本质上充当一个占位符,允许 PL/pgSQL 引擎在不触发语法错误的情况下计算条件。

-- the condition is evaluated as SQL,
-- "and" is treated as column alias

SELECT 0 = 0 AND;
 and
-----
 t
(1 row)

这种见解 — 条件表达式作为SELECT语句进行计算 — 开辟了新的可能性。这意味着,我们可以在 PL/pgSQL 的条件中利用各种函数,如以下示例所示。

以下代码片段说明了,在 PL/pgSQL 中计算条件表达式的不同方式:

条件 SQL PL/pgSQL
计数求值 select count(1) = 1; do $$
begin
if count(1) = 1 and then
raise notice ‘%’,‘Matched If Clause’;
else raise notice ‘Not Match If Clase’;
end if;
end;$$;
不区分大小写的匹配 select (‘a’ ilike ‘A’); do $$
begin
if (‘a’ ilike ‘A’) and then
raise notice ‘%’,‘Matched If Clause’;
else raise notice ‘Not Match If Clase’;
end if;
end;$$;
复杂的 unnest – 基于数组的条件 select COUNT(col1) filter(where col1 = ‘A’) = 2 from (select unnest(ARRAY[‘A’,‘B’,‘A’]) col1) do $$
begin
if COUNT(col1) filter(where col1 = ‘A’) = 2 from (select unnest(ARRAY[‘A’,‘B’,‘A’]) col1) then
raise notice ‘%’, ‘Matched If Clause’;
else raise notice ‘Not Match If Clase’;
end if;
end;$$;
行存在性检查 select exists (select 1 from generate_series(1,10000)); do $$
begin
if exists (select 1 from generate_series(1, 10000)) then
raise notice ‘%’, ‘Matched If Clause’;
else raise notice ‘Not Match If Clase’;
end if;
end;$$;

结论

PL/pgSQL 使用SELECT语句处理条件表达式,允许不完整的条件(如IF i = 0 AND)无错误地执行。

条件中的AND并没有出错,而是将其作为了SELECT表达式的一部分,让 PostgreSQL 灵活地计算它。这种方法允许开发者将各种SELECT表达式直接融入到条件计算中,从而提供了其他的方法,可在 PL/pgSQL 中无缝构建和测试复杂逻辑。