事件触发器将触发器应用于新表

问题描述 投票:0回答:2

我正在尝试实现自动将触发器应用于任何新的“项目”表的功能 正如它们被创建一样。

我尝试使用

EVENT TRIGGER
来做到这一点,首先使用这个功能:

CREATE OR REPLACE FUNCTION public.apply_trigger_on_item_table_creation()
RETURNS event_trigger AS $$
DECLARE
    obj record;
BEGIN
    FOR obj IN
        SELECT * FROM pg_event_trigger_ddl_commands()
    LOOP
        IF obj.object_type = 'table' AND obj.object_identity LIKE '%.items' THEN
            EXECUTE format('
                CREATE OR REPLACE TRIGGER item_create_trigger
                AFTER INSERT ON %I
                FOR EACH ROW
                EXECUTE FUNCTION public.sync_insert();', obj.object_identity);
        END IF;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

然后创建了一个事件触发器

ON ddl_command_end
:

CREATE EVENT TRIGGER create_item_table_trigger
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE')
EXECUTE FUNCTION apply_trigger_on_item_table_creation();

但是,当我尝试执行

CREATE TABLE test.items
时,我收到以下错误:

ERROR:  relation "test.items" does not exist
CONTEXT:  SQL statement "
                CREATE OR REPLACE TRIGGER item_create_trigger
                AFTER INSERT ON "test.items"
                FOR EACH ROW
                EXECUTE FUNCTION public.sync_insert();"
PL/pgSQL function apply_trigger_on_wi_table_creation() line 12 at EXECUTE 
SQL state: 42P01

尽管这个触发器被称为

ON ddl_command_end
,但在触发器退出之前该表并不存在。

这个问题有原生 PostgreSQL 解决方案吗?也许使用

LISTEN/NOTIFY
?谢谢!

postgresql triggers eventtrigger
2个回答
0
投票

问题在于

"test.items"
中的双引号使数据库将此作为表名,而不是模式限定表(这将是
test.items
"test"."items"
)。

文档这么说

姓名 类型 描述
... ... ...
object_identity
text
对象标识的文本呈现,模式限定。如有必要,身份中包含的每个标识符都会被引用。

所以你可以像

一样使用
%s

EXECUTE format(
           E'CREATE TRIGGER item_create_trigger\n'
           'AFTER INSERT ON %s\n'
           'FOR EACH ROW\n'
           'EXECUTE FUNCTION public.sync_insert();',
           obj.object_identity
        );

0
投票

正如 Frank Heikens 指出的那样,问题不在于时间,而在于架构 + 表名称作为单个字符串写入

CREATE TRIGGER
SQL(
"test.items"
而不是
test.items
)。

为了解决此问题,我对

apply_trigger_on_item_table_creation()
进行了以下更改:

  1. 为分离的模式和表名称声明变量:
DECLARE
    obj record;
    new_schema TEXT;
    new_table TEXT;
  1. 拆分
    obj.object_identity
new_schema := split_part(obj.object_identity, '.', 1);
new_table := split_part(obj.object_identity, '.', 2);
  1. 修改格式以接受 2 个身份占位符:
EXECUTE format('
    CREATE OR REPLACE TRIGGER item_create_trigger
    AFTER INSERT ON %I.%I
    FOR EACH ROW
    EXECUTE FUNCTION public.sync_insert();', new_schema, new_table);
© www.soinside.com 2019 - 2024. All rights reserved.