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

PostgreSQL document说:

The entire body of a SQL function is parsed before any of it is executed. While a SQL function can contain commands that alter the
system catalogs
(e.g., CREATE TABLE), the effects of such commands
will not be visible during parse analysis of later commands in the
function. Thus, for example, CREATE TABLE foo (...); INSERT INTO foo VALUES(...);
will not work as desired if packaged up into a single
SQL function
, since foo won’t exist yet when the INSERT command is parsed.

It’s recommended to use PL/pgSQL instead of a SQL function
in this type of situation.

>为什么“在这种情况下,建议使用PL / pgSQL代替SQL函数”,其中PL / pgSQL或SQL函数包含更改系统目录的命令,例如CREATE TABLE foo(…);插入foo VALUES(…); ?
>“在执行任何SQL函数之前先对其进行分析”. PL / pgSQL函数不是真的吗?在解析和执行其主体中的命令方面,SQL函数和PL / pgSQL函数之间有什么区别?

最佳答案
您自己加粗了key sentence in the manual

The entire body of a SQL function is parsed before any of it is executed.

另请参阅约The Parser Stage in the manual.

它由两个主要部分组成:解析器和转换过程. Quoting the manual:

the transformation process takes the tree handed back by the parser as
input and does the semantic interpretation needed to understand which
tables, functions, and operators are referenced by the query.

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

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

几乎同时计划了这两个语句(基于系统目录的相同快照).因此,INSERT无法看到使用上一个CREATE命令创建的表“ foo”.这就产生了以下问题之一:

>如果没有其他名为“ foo”的表in your search_patch(尚未),则Postgres在尝试创建函数时会抱怨:

06001

>如果search_patch中已经存在另一个名为“ foo”的表(并且您没有使用冲突的列名),则Postgres将基于该表来计划INSERT.如果任何值导致(错误!)表中的冲突,通常会在执行时导致错误.或者,如果运气不好,它甚至可能在没有错误消息的情况下写入该表!非常狡猾的错误.

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

因此,与SQL函数不同,从未访问过的语句甚至都不会被计划.语句的执行计划可以缓存在同一会话中-与SQL函数不同. Read details about plan caching in PL/pgSQL functions in the manual here.
对于某些用例,每种方法都具有优势.进一步阅读:

> Difference between language sql and language plpgsql in PostgreSQL functions

转载注明原文:为什么PL / pgSQL函数会有副作用,而SQL函数却没有? - 代码日志