以非特权用户身份使用 postgres 扩展

问题描述

问题

我有以下使用 moddatetime 扩展名的触发器函数

/* BEFORE UPDATE trigger - Updates "entity_version.updated_on",setting it to the current UTC time. */
CREATE EXTENSION IF NOT EXISTS moddatetime;  -- Needs superuser privileges!

DROP TRIGGER IF EXISTS trig_entity_version_before_update
ON entity_version;

CREATE TRIGGER trig_entity_version_before_update
    BEFORE UPDATE
    ON entity_version
    FOR EACH ROW EXECUTE PROCEDURE moddatetime(updated_on);  -- updated_on is TIMESTAMP type

触发器工作正常,但问题是第一行 (CREATE EXTENSION) 需要超级用户权限。由于这些数据库将由用户(通过脚本)创建,我不希望他们成为创建这些数据库和触发器的用户具有超级用户访问权限。

我的尝试

作为第一步,如您所料,以超级用户身份运行脚本可以正常工作。

当然,下一步是将扩展作为超级用户的创建与触发器创建脚本分开。但是这样做,如果我在没有 CREATE EXTENSION 行的情况下运行上面的脚本,我会收到以下错误

function moddatetime() does not exist

鉴于脚本从未声明 moddatetime,我认为这是有道理的,但我在文档中找不到任何地方如何在不使用 CREATE EXTENSION 的情况下将扩展定义为可用。当然必须有一种方法可以导入或使用扩展而无需创建它?类似于:

USING EXTENSION moddatetime;  -- Does something like this exist?

... rest of the trigger script ...

解决方法

如果你想使用它,你需要安装扩展。

PostgreSQL v13 引入了可信扩展的概念,可以由对数据库具有 CREATE 权限的非超级用户安装,但此扩展不在其中。所以升级并不能解决问题。

您可以以超级用户身份连接到 template1 并在那里创建扩展。然后它会自动出现在所有新创建的数据库中。

但坦率地说,我不明白这一点。您可以使用常规的 PL/pgSQL 触发器来做同样的事情——只是性能不会那么好。

,

根据@laurenz-albe 他的建议,我刚刚停止使用此特定用例的扩展。幸运的是,编写一个函数来完成扩展所做的事情是相对简单的。如果有人特别想替换 moddatetime,我会将其包含在此处以供参考。

DROP FUNCTION IF EXISTS fn_entity_version_before_update() CASCADE;

CREATE FUNCTION fn_entity_version_before_update() RETURNS TRIGGER LANGUAGE PLPGSQL AS
$fn_body$
BEGIN
    NEW.updated_on = NOW() AT TIME ZONE 'utc';
    RETURN NEW;
END;
$fn_body$;

DROP TRIGGER IF EXISTS trig_entity_version_before_update
ON entity_version;

CREATE TRIGGER trig_entity_version_before_update
    BEFORE UPDATE
    ON entity_version
    FOR EACH ROW EXECUTE PROCEDURE fn_entity_version_before_update();

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...