一尘不染

为什么PL / pgSQL函数会有副作用,而SQL函数却没有?

sql

PostgreSQL文件说:

SQL函数的整个主体在执行任何函数之前都会被解析。 虽然SQL函数可以包含 更改系统目录的命令 (例如CREATE TABLE),但是在对函数中的后续命令进行语法分析时,这些命令的效果将不可见。因此,例如, CREATE TABLE foo (...); INSERT INTO foo VALUES(...); 如果打包到单个SQL函数中将无法按预期工作
,因为INSERT解析命令时foo尚不存在。

在这种情况下,建议使用PL / pgSQL代替SQL函数。

  • 为什么“在这种情况下,建议使用PL / pgSQL代替SQL函数”,而PL / pgSQL或SQL函数包含更改系统目录的命令,例如CREATE TABLE foo (...); INSERT INTO foo VALUES(...);

  • “ SQL函数的整个主体在执行任何函数之前都会被解析”。PL / pgSQL函数不是真的吗?在解析和执行其主体中的命令方面,SQL函数和PL / pgSQL函数之间有什么区别?


阅读 132

收藏
2021-03-10

共1个答案

一尘不染

您自己将手册中关键句子加粗了:

SQL函数的整个主体在执行任何函数之前都会被解析。

另请参阅手册中有关
解析器阶段 的信息

它由两个主要部分组成: 解析器转换过程
引用手册:

改造过程中 需要由解析器树递回作为输入,并确实了解哪些表,函数,和运营商查询所引用所需的语义解释。

如果SQL函数包含以下命令:

CREATE TABLE foo (...);
INSERT INTO foo VALUES(...);

几乎同时计划了这两个语句(基于系统目录的相同快照)。因此,INSERT不能看到表“ foo”可能是由上一条CREATE命令创建的。这就产生
了以下问题之一

  1. 如果没有 其他的 名为“foo”表在你search_patch(还),Postgres的抱怨 试图创建时 的功能:
ERROR:  relation "foo" does not exist
  1. 如果您的表中已经存在另一个名为“ foo”的表search_patch(并且您不使用冲突的列名),则Postgres将INSERT基于该表进行计划。如果任何值导致(错误!)表中的冲突,通常会 在执行时 导致错误。或者,如果运气不好,它甚至可能在没有错误消息的情况下写入该表!非常偷偷摸摸的错误。

使用 PL / pgSQL 函数不会发生这种情况,因为它会将SQL命令像预处理语句一样按 _ 顺序_
计划和执行。因此,每个语句都可以查看在先前语句中创建的对象。

因此,从未访问过的语句甚至都不会被计划-与SQL函数不同。语句的执行计划可以缓存在同一会话中-与SQL函数不同。在此处阅读有关PL /
pgSQL函数中计划缓存的详细信息。

2021-03-10