以非特权用户身份使用 postgres 扩展
Use a postgres extension as a non-privileged user
问题
我有以下使用 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
鉴于脚本从未声明 [=13=],我认为这是有道理的,但我无法在文档中的任何地方找到如何在不使用 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();
问题
我有以下使用 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
鉴于脚本从未声明 [=13=],我认为这是有道理的,但我无法在文档中的任何地方找到如何在不使用 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();