我正在尝试实现自动将触发器应用于任何新的“项目”表的功能 正如它们被创建一样。
我尝试使用
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
?谢谢!
问题在于
"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
);
正如 Frank Heikens 指出的那样,问题不在于时间,而在于架构 + 表名称作为单个字符串写入
CREATE TRIGGER
SQL("test.items"
而不是 test.items
)。
为了解决此问题,我对
apply_trigger_on_item_table_creation()
进行了以下更改:
DECLARE
obj record;
new_schema TEXT;
new_table TEXT;
obj.object_identity
:new_schema := split_part(obj.object_identity, '.', 1);
new_table := split_part(obj.object_identity, '.', 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);