如何在 PostgreSQL 8.2 中动态使用 TG_TABLE_NAME?
我正在尝试在 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;
按照当前编写的方式,我必须为每个表编写一个单独的触发器函数。我想使用 TG_TABLE_NAME 动态构建我的 INSERT 语句,并在其前面加上“cdc_”前缀,因为所有表都遵循相同的命名约定。然后我可以让每个表的每个触发器只调用一个函数。
I am trying to write a trigger function in PostgreSQL 8.2 that will dynamically use TG_TABLE_NAME to generate and execute a SQL statement. I can find all kinds of examples for later versions of PostgreSQL, but I am stuck on 8.2 because of some requirements. Here is my function as it stands which works, but is hardly dynamic:
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;
The way this is currently written, I would have to write a separate trigger function for every table. I would like to use TG_TABLE_NAME to dynamically build my INSERT statement and just prefix it with 'cdc_' since all of the tables follow the same naming convention. Then I can have every trigger for every table call just one function.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
几年前我一直在寻找完全相同的东西。一种触发功能即可统治一切!我在 usenet 列表上询问,尝试了各种方法,但无济于事。关于此事的共识是这是不可能的。 PostgreSQL 8.3 或更早版本的一个缺点。
自 PostgreSQL 8.4< /strong> 你可以:
使用 pg 8.2,你遇到一个问题:
NEW
/OLD
列。你需要知道编写触发器函数时的列名称。
NEW
/OLD
在EXECUTE
内不可见。EXECUTE .. USING
尚未诞生。然而,有一个技巧。
系统中的每个表名都可以作为同名的复合类型。因此,您可以创建一个以
NEW
/OLD
作为参数的函数并执行它。您可以在每个触发事件上动态创建和销毁该函数:触发函数:
触发器:
表名称必须像用户输入一样对待。使用
quote_ident()
来防御SQL注入。但是,通过这种方式,您可以为每个触发事件创建并删除一个函数。相当大的开销,我不会这么做。您将不得不经常清理一些目录表。
中间立场
PostgreSQL 支持函数重载。因此,每个表的一个具有相同基本名称(但参数类型不同)的函数可以共存。您可以采取中间立场,通过在创建触发器的同时为每个表创建一次
f_cdc(..)
来显着减少噪音。这是每张桌子的一个小功能。您必须观察表定义的更改,但表不应经常更改。从触发器函数中删除CREATE
和DROP FUNCTION
,得到一个小、快速、优雅的触发器。我可以在第 8.2 页中看到自己这样做。除了我无法再在 8.2 pg 中看到自己做任何事情。它已于 2011 年 12 月结束。也许你毕竟可以以某种方式升级。
I was looking for the exact same thing a couple of years back. One trigger function to rule them all! I asked on usenet lists, tried various approaches, to no avail. The consensus on the matter was this could not be done. A shortcoming of PostgreSQL 8.3 or older.
Since PostgreSQL 8.4 you can just:
With pg 8.2 you have a problem:
NEW
/OLD
. You need to knowcolumn names at the time of writing the trigger function.
NEW
/OLD
are not visible insideEXECUTE
.EXECUTE .. USING
not born yet.There is a trick, however.
Every table name in the system can serve as composite type of the same name. Therefore you can create a function that takes
NEW
/OLD
as parameter and execute that. You can dynamically create and destroy that function on every trigger event:Trigger function:
Trigger:
Table names have to be treated like user input. Use
quote_ident()
to defend against SQL injection.However, this way you create and drop a function for every single trigger event. Quite an overhead, I would not go for that. You will have to vacuum some catalog tables a lot.
Middle ground
PostgreSQL supports function overloading. Therefore, one function per table of the same base name (but different parameter type) can coexist. You could take the middle ground and dramatically reduce the noise by creating
f_cdc(..)
once per table at the same time you create the trigger. That's one tiny function per table. You have to observe changes of table definitions, but tables shouldn't change that often. RemoveCREATE
andDROP FUNCTION
from the trigger function, arriving at a small, fast and elegant trigger.I could see myself doing that in pg 8.2. Except that I cannot see myself doing anything in pg 8.2 anymore. It has reached end of life in December 2011. Maybe you can upgrade somehow after all.
几年前我也问过类似的问题。
看看这个问题,看看它是否给你任何有用的想法:
使用 PL/pgsql 中的 EXECUTE 从通用触发器插入 NEW.*
I also asked a similar question a couple of years ago.
Have a look at that question and see if it gives you any useful ideas:
Inserting NEW.* from a generic trigger using EXECUTE in PL/pgsql