Rob*_*Rob 6 sql postgresql triggers function plpgsql
我试图在PostgreSQL 8.2中编写一个触发器函数,它将动态使用TG_TABLE_NAME来生成和执行SQL语句.我可以为PostgreSQL的更高版本找到各种各样的例子,但由于一些要求,我被困在8.2上.这是我的功能,因为它有效,但几乎没有动态:
CREATE OR REPLACE FUNCTION cdc_TABLENAME_function() RETURNS trigger AS $cdc_function$
DECLARE
op cdc_operation_enum;
BEGIN
op = TG_OP;
IF (TG_WHEN = 'BEFORE') THEN
IF (TG_OP = 'UPDATE') THEN
op = 'UPDATE_BEFORE';
END IF;
INSERT INTO cdc_test VALUES (DEFAULT,DEFAULT,op,DEFAULT,DEFAULT,OLD.*);
ELSE
IF (TG_OP = 'UPDATE') THEN
op = 'UPDATE_AFTER';
END IF;
INSERT INTO cdc_test VALUES (DEFAULT,DEFAULT,op,DEFAULT,DEFAULT,NEW.*);
END IF;
IF (TG_OP = 'DELETE') THEN
RETURN OLD;
ELSE
RETURN NEW;
END IF;
END;
Run Code Online (Sandbox Code Playgroud)
这是当前编写的方式,我将不得不为每个表编写一个单独的触发器函数.我想使用TG_TABLE_NAME来动态构建我的INSERT语句,并在其前面加上'cdc_',因为所有表都遵循相同的命名约定.然后我可以让每个表调用的每个触发器只有一个函数.
Erw*_*ter 13
几年前我一直在寻找同样的东西.一个触发器功能来统治它们!我问过usenet列表,尝试了各种方法,但无济于事.关于此事的共识是无法做到的.PostgreSQL 8.3或更早版本的缺点.
EXECUTE 'INSERT INTO ' || TG_RELID::regclass::text || ' SELECT ($1).*'
USING NEW;
Run Code Online (Sandbox Code Playgroud)
使用第8.2页,您有一个问题:
NEW/的列OLD.您需要在编写触发器功能时知道列名称. NEW/ OLD在里面看不到EXECUTE.EXECUTE .. USING 还没出生.系统中的每个表名都可以作为同名的复合类型.因此,您可以创建一个以NEW/ OLD作为参数并执行该函数的函数.您可以在每个触发事件上动态创建和销毁该函数:
触发功能:
CREATE OR REPLACE FUNCTION trg_cdc()
RETURNS trigger AS
$func$
DECLARE
op text := TG_OP || '_' || TG_WHEN;
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(TG_TABLE_NAME);
cdc_tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident('cdc_' || TG_TABLE_NAME);
BEGIN
EXECUTE 'CREATE FUNCTION f_cdc(n ' || tbl || ', op text)
RETURNS void AS $x$ BEGIN
INSERT INTO ' || cdc_tbl || ' SELECT op, (n).*;
END $x$ LANGUAGE plpgsql';
CASE TG_OP
WHEN 'INSERT', 'UPDATE' THEN
PERFORM f_cdc(NEW, op);
WHEN 'DELETE' THEN
PERFORM f_cdc(OLD, op);
ELSE
RAISE EXCEPTION 'Unknown TG_OP: "%". Should not occur!', TG_OP;
END CASE;
EXECUTE 'DROP FUNCTION f_cdc(' || tbl || ', text)';
IF TG_OP = 'DELETE' THEN
RETURN OLD;
ELSE
RETURN NEW;
END IF;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
触发:
CREATE TRIGGER cdc
BEFORE INSERT OR UPDATE OR DELETE ON my_tbl
FOR EACH ROW EXECUTE PROCEDURE trg_cdc();
Run Code Online (Sandbox Code Playgroud)
表名必须像用户输入一样对待.使用quote_ident()防御SQL注入.
但是,这样您就可以为每个触发事件创建和删除一个函数.相当大的开销,我不会那样做.你将不得不抽真空一些目录表.
PostgreSQL支持函数重载.因此,每个具有相同基本名称(但不同参数类型)的表的一个函数可以共存.通过f_cdc(..)在创建触发器的同时为每个表创建一次,您可以占据中间位置并显着降低噪声.这是每张桌子的一个小功能.您必须观察表定义的更改,但表不应经常更改.取出CREATE并DROP FUNCTION从触发功能,到达一个小型,快速,优雅的触发.
我可以看到自己在第8.2页中这样做.除了我不能再看到自己在第8.2页做任何事情.它已于2011年12月达到使用寿命.也许你可以以某种方式升级.