由 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 中无缝构建和测试复杂逻辑。