首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在PostgreSQL 8.2中动态使用TG_TABLE_NAME?

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

Stack Overflow用户
提问于 2011-09-23 01:38:00
回答 2查看 12.4K关注 0票数 8

我正在尝试用SQL8.2编写一个触发器函数,它将动态地使用TG_TABLE_NAME来生成和执行PostgreSQL语句。我可以找到更高版本的PostgreSQL的各种示例,但由于一些要求,我被困在8.2版本上。下面是我的函数,它可以工作,但几乎不是动态的:

代码语言:javascript
运行
复制
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;

按照目前的编写方式,我必须为每个表编写一个单独的触发器函数。我想使用TG_TABLE_NAME来动态构建我的INSERT语句,并且只使用'cdc_‘作为它的前缀,因为所有的表都遵循相同的命名约定。然后,我可以让每个表调用的每个触发器只有一个函数。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-10-01 09:25:29

几年前我也在找同样的东西。一个触发器函数就可以控制所有的触发器!我在usenet列表上询问,尝试了各种方法,但都无济于事。在这件事上的共识是这是不可能做到的。PostgreSQL 8.3或更早版本的缺点。

Since PostgreSQL 您只需:

代码语言:javascript
运行
复制
EXECUTE 'INSERT INTO ' || TG_RELID::regclass::text || ' SELECT ($1).*'
USING NEW;

使用pg 8.2时,您会遇到一个问题:

  • 无法动态访问NEW / OLD的列。您需要知道在编写触发器时function.
  • NEW / OLDEXECUTE.
  • EXECUTE .. USING not born中不可见的列名。

然而,这里有一个诀窍。

系统中的每个表名都可以作为同名的复合类型。因此,您可以创建一个以NEW / OLD为参数的函数并执行该函数。您可以在每个触发器事件上动态创建和销毁该函数:

触发器功能:

代码语言:javascript
运行
复制
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;

触发器:

代码语言:javascript
运行
复制
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(..),从而大大减少噪音。这是每个表的一个小函数。您必须观察表定义的更改,但是表不应该经常更改。从触发器函数中去掉CREATEDROP FUNCTION,得到一个小巧、快速、优雅的触发器。

我可以想象我自己在第8.2页中这样做。除了我再也看不到自己在pg 8.2中做任何事情。它有reached end of life in December 2011。也许你终究还是可以升级的。

票数 15
EN

Stack Overflow用户

发布于 2011-10-03 07:26:44

几年前我也问过类似的问题。

看一下这个问题,看看它是否给了你任何有用的想法:

Inserting NEW.* from a generic trigger using EXECUTE in PL/pgsql

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7519044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档