在执行任何一个SQL函数之前都会对它的整个体进行解析。函数可以包含改变系统目录(例如
CREATE TABLE)的命令,但是在解析函数中的后续命令时,这些命令的效果是不可见的。因此,例如,如果将CREATE TABLE foo (...); INSERT INTO foo VALUES(...);打包到单个SQL函数中,则不会按需要工作,因为解析INSERT命令时foo还不存在。 在这种情况下建议使用PL/pgSQL而不是SQL函数。
CREATE TABLE foo (...); INSERT INTO foo VALUES(...);?发布于 2018-06-26 01:56:32
你自己用粗体显示了手册中的关键句子:
一个SQL函数的整个主体在执行任何一个.之前都会被解析。
还可以读到关于在手册中的文章。
它由两个主要部分组成:解析器和转换过程。引用手册:
转换过程将解析器返回的树作为输入,并执行所需的语义解释,以理解查询引用了哪些表、函数和操作符。
如果SQL函数包含以下命令:
CREATE TABLE foo (...);
INSERT INTO foo VALUES(...);这两个语句实际上是在同一时间计划的(基于系统目录的相同快照)。因此,INSERT无法看到表"foo“可能是用前面的CREATE命令创建的。这会造成()以下问题之一
search_patch (尚未)的表,Postgres在尝试创建函数时会抱怨:
错误:关系"foo“不存在search_patch中已经存在另一个名为"foo“的表(并且不使用相互冲突的列名),Postgres将根据该预先存在的表规划INSERT。通常,如果任何值导致(错误!)中的冲突,则在执行时导致错误!表格。或者,如果运气不好,它甚至可以在没有错误消息的情况下写入该表!很狡猾的虫子。这在sequentially. PL/pgSQL函数中是不可能发生的,因为它将命令视为准备好的语句、计划好的和执行的。因此,每个语句都可以看到以前语句中创建的对象。
因此,从未访问过的语句甚至从未计划过--与SQL函数不同。语句的执行计划可以在同一个会话中缓存--也不同于SQL函数。阅读手册中关于PL/pgSQL函数中的计划缓存的详细信息。
对于某些用例,每种方法都有其优点。进一步读:
发布于 2018-06-23 21:57:30
在定义时解析Plpgsql函数并检查语法,然后在第一次执行时生成计划。
https://www.postgresql.org/docs/current/static/plpgsql-implementation.html#PLPGSQL-PLAN-CACHING
然后用给定的参数执行该计划。
除了第一次执行时已经存在的文件外,临时文件似乎像预期的那样工作。
如前所述,使用动态SQL (EXECUTE)是阻止计划器访问任意表的一种方法。
https://stackoverflow.com/questions/51004980
复制相似问题