使用临时表的函数的物化视图

Prz*_*mek 5 postgresql postgresql-9.6

我有一个存储过程,它在其主体中使用一个临时表。尝试使用此过程创建物化视图,例如

CREATE MATERIALIZED VIEW my_view AS SELECT * FROM my_function;
Run Code Online (Sandbox Code Playgroud)

给我一个错误:

ERROR:  cannot create temporary table within security-restricted operation
Run Code Online (Sandbox Code Playgroud)

它在源代码的注释中进行了解释:

/*
 * Security check: disallow creating temp tables from security-restricted
 * code.  This is needed because calling code might not expect untrusted
 * tables to appear in pg_temp at the front of its search path.
 */
Run Code Online (Sandbox Code Playgroud)

除了重新处理存储过程本身以不使用临时表之外,还有其他解决方法吗?

Kam*_*ski 6

此限制背后的想法是防止刷新物化视图后会话状态的更改。这实际上在您从源代码中添加的注释中进行了解释(尽管它可能会令人困惑)。

换句话说,这意味着即使已存在同名的常规表,查询也可能会选取一个新的临时表(您可以在函数中创建)。查找表时pg_temp隐式添加架构SEARCH PATH


我能想到的解决方法有两种:

  1. 使用普通表而不是临时表。您可以指定UNLOGGED以获得更好的性能。

示例代码:

CREATE FUNCTION my_function()
RETURNS BOOLEAN
LANGUAGE 'plpgsql'
AS '
BEGIN
    DROP TABLE IF EXISTS my_tmp_table;
    CREATE UNLOGGED TABLE my_tmp_table(a int); -- regular unlogged table
    RETURN TRUE;
END';

CREATE MATERIALIZED VIEW my_view AS SELECT * FROM my_function(); -- materialized view
Run Code Online (Sandbox Code Playgroud)
  1. 代替物化视图,创建一个常规表,然后在需要刷新时删除并重新创建它

示例代码:

CREATE FUNCTION my_function()
RETURNS BOOLEAN
LANGUAGE 'plpgsql'
AS '
BEGIN
    DROP TABLE IF EXISTS my_tmp_table;
    CREATE TEMP TABLE my_tmp_table(a int); -- temp table
    RETURN TRUE;
END';

CREATE TABLE my_view AS SELECT * FROM my_function(); -- table, not a view
Run Code Online (Sandbox Code Playgroud)