加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何在PostgreSQL 8.2中动态使用TG_TABLE_NAME?

发布时间:2020-12-13 18:07:52 所属栏目:百科 来源:网络整理
导读:我试图在PostgreSQL 8.2中编写一个触发器函数,它将动态使用TG_TABLE_NAME来生成和执行SQL语句.我可以为PostgreSQL的更高版本找到各种各样的例子,但由于一些要求,我被困在8.2上.这是我的功能,因为它有效,但几乎没有动态: CREATE OR REPLACE FUNCTION cdc_TAB
我试图在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,OLD.*); 
        ELSE
            IF (TG_OP = 'UPDATE') THEN
                op = 'UPDATE_AFTER';
            END IF;

            INSERT INTO cdc_test VALUES (DEFAULT,NEW.*); 
        END IF;

        IF (TG_OP = 'DELETE') THEN
            RETURN OLD;
        ELSE
            RETURN NEW;
        END IF;
    END;

这是当前编写的方式,我将不得不为每个表编写一个单独的触发器函数.我想使用TG_TABLE_NAME来动态构建我的INSERT语句,并在其前面加上’cdc_’,因为所有表都遵循相同的命名约定.然后我可以让每个表调用的每个触发器只有一个函数.

几年前我一直在寻找同样的东西.一个触发器功能来统治它们!我问过usenet列表,尝试了各种方法,但无济于事.关于此事的共识是无法做到的. PostgreSQL 8.3或更早版本的缺点.

Since PostgreSQL 8.4你可以:

EXECUTE 'INSERT INTO ' || TG_RELID::regclass::text || ' SELECT ($1).*'
USING NEW;

使用第8.2页,您有一个问题:

>无法动态访问NEW / OLD列.你得知道
写入触发器功能时的列名.
>在EXECUTE内部看不到NEW / OLD.
>执行..使用尚未出生.

然而,有一个技巧.

系统中的每个表名都可以作为同名的复合类型.因此,您可以创建一个将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;

触发:

CREATE TRIGGER cdc
BEFORE INSERT OR UPDATE OR DELETE ON my_tbl
FOR EACH ROW EXECUTE PROCEDURE trg_cdc();

表名必须像用户输入一样对待.使用quote_ident()来防止SQL注入.

但是,这样您就可以为每个触发事件创建和删除一个函数.相当大的开销,我不会那样做.你将不得不抽真空一些目录表.

中间地带

PostgreSQL支持function overloading.因此,每个具有相同基本名称(但不同参数类型)的表的一个函数可以共存.通过在创建触发器的同时为每个表创建一次f_cdc(..),您可以占据中间位置并显着降低噪声.这是每张桌子的一个小功能.您必须观察表定义的更改,但表不应经常更改.从触发器功能中删除CREATE和DROP FUNCTION,达到一个小巧,快速和优雅的触发器.

我可以看到自己在第8.2页中这样做.除了我不能再看到自己在第8.2页做任何事情.它有reached end of life in December 2011.也许你可以以某种方式升级.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读