- 什么是触发器? 触发器有什么用? 创建触发器的语法?
- 什么是触发器函数, 触发器函数可以用哪些语言编写?
- 触发器有哪些分类?
- 同一个表或视图上可以建多少个触发器? 如果一个表或视图上有多个触发器, 调用顺序如何决定?
- 同一个触发器函数可以被多个触发器调用吗? 触发器函数的返回类型时什么? 触发器函数的返回值是否会影响下一个触发器函数或者被操作的行的数据? NEW 或者OLD record修改后会带来什么影响? 哪些触发器函数的返回值没有意义?
- 触发器函数的返回值与返回行数的关系, 与变量FOUND, ROW_COUNT, RETURNING的关系.
- 触发器的延时属性和状态.
- 可以在系统表或系统视图上创建触发器吗?
- 触发器函数的返回值.
- 触发器函数的参数.
- 触发器函数中的变量与传递.
- 触发器函数的数据可视与什么有关?
- 触发器会无限递归吗? 如何避免?
- 触发条件与性能.
- 加入触发器后的事务特性.
- 触发器的返回值是如何影响returning的结果的?
- 什么是触发器? 触发器有什么用? 创建触发器的语法?
定义还是用原文比较好 :
A trigger is a specification that the database should automatically execute a particular function whenever a certain type of operation is performed.
Triggers can be attached to both tables and views.
Command: CREATE TRIGGER
Description: define a new trigger
Syntax:
CREATE [ CONSTRAINT ] TRIGGER name { BEFORE | AFTER | INSTEAD OF } { event [ OR ... ] }
ON table_name
[ FROM referenced_table_name ]
{ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } }
[ FOR [ EACH ] { ROW | STATEMENT } ]
[ WHEN ( condition ) ]
EXECUTE PROCEDURE function_name ( arguments )
where event can be one of:
INSERT
UPDATE [ OF column_name [, ... ] ]
DELETE
TRUNCATE
- 什么是触发器函数? 触发器函数可以用哪些语言编写?
给表或者视图创建触发器时需要指定这个触发器被触发时执行的函数, 这个函数就是触发器函数.
触发器函数的返回类型为trigger, 如果需要给触发器函数传入参数, 不能定义在触发器函数的参数列表中, 而是通过其他方式传入(TriggerData数据结构).
例如使用plpgsql写的触发器函数, 通过变量TG_ARGV[]来接收传入的变量值.
The trigger function must be defined before the trigger itself can be created. The trigger function must be declared as a function taking no arguments and returning type trigger. (The trigger function receives its input through a specially-passed TriggerData structure, not in the form of ordinary function arguments.)
typedef struct TriggerData
{
NodeTag type;
TriggerEvent tg_event;
Relation tg_relation;
HeapTuple tg_trigtuple;
HeapTuple tg_newtuple;
Trigger *tg_trigger;
Buffer tg_trigtuplebuf;
Buffer tg_newtuplebuf;
} TriggerData;
/*Trigger数据结构, 传入的参数数据结构 : */
typedef struct Trigger
{
Oid tgoid; /* OID of trigger (pg_trigger row) */
/* Remaining fields are copied from pg_trigger, see pg_trigger.h */
char *tgname;
Oid tgfoid;
int16 tgtype;
char tgenabled;
bool tgisinternal;
Oid tgconstrrelid;
Oid tgconstrindid;
Oid tgconstraint;
bool tgdeferrable;
bool tginitdeferred;
int16 tgnargs;
int16 tgnattr;
int16 *tgattr;
char **tgargs;
char *tgqual;
} Trigger;
On tables, triggers can be defined to execute either before or after any INSERT, UPDATE, or DELETE operation, either once per modified row, or once per SQL statement.
UPDATE triggers can moreover be set to fire only if certain columns are mentioned in the SET clause of the UPDATE statement.
Triggers can also fire for TRUNCATE statements.
If a trigger event occurs, the trigger's function is called at the appropriate time to handle the event.
(before | after) (INSERT | UPDATE | DELETE) (FOR EACH ROW) (WHEN NEW.? and,or OLD.? ... other boolean express ....)
(before | after) (INSERT | UPDATE | DELETE | TRUNCATE) (FOR EACH STATEMENT) (WHEN BOOLEAN express except NEW or OLD or columns)
On views, triggers can be defined to execute instead of INSERT, UPDATE, or DELETE operations.
INSTEAD OF triggers are fired once for each row that needs to be modified in the view.
It is the responsibility of the trigger's function to perform the necessary modifications to the underlying base tables and, where appropriate, return the modified row as it will appear in the view.
Triggers on views can also be defined to execute once per SQL statement, before or after INSERT, UPDATE, or DELETE operations.
(INSTEAD OF) (INSERT | UPDATE | DELETE) (FOR EACH ROW) (WHEN NEW.? and,or OLD.? ... other boolean express ....)
(before | after) (INSERT | UPDATE | DELETE) (FOR EACH STATEMENT) (WHEN BOOLEAN express except NEW or OLD or columns)
When Event Row-level Statement-level
BEFORE INSERT/UPDATE/DELETE Tables Tables and views
TRUNCATE — Tables
AFTER INSERT/UPDATE/DELETE Tables Tables and views
TRUNCATE — Tables
INSTEAD OF INSERT/UPDATE/DELETE Views —
TRUNCATE — —
同一个表或视图上可以建多个触发器吗? 如果一个表或视图上有多个触发器, 调用顺序如何决定?
同一个表或视图上可以创建多个触发器, 调用的顺序和触发器的类型有关.
表上各种触发器的调用先后顺序如下 :
before for each statement
2. before for each row
3. after for each row
4. after for each statement
视图上各种触发器的调用先后顺序如下 :
before for each statement
2. instead for each row
3. after for each statement
同类触发器如果有多个, 调用顺序则和触发器的名字有关, 按照名字的排序进行调用.
举例, 使用raise notice TG_NAME跟踪调用顺序 :
// 表举例 // 创建测试表 postgres=# create table digoal (id int); CREATE TABLE // 创建触发器函数 postgres=# create or replace function debug() returns trigger as $$ declare begin raise notice '%', TG_NAME; return new; end; $$ language plpgsql; CREATE FUNCTION //k // 创建4种类型的触发器 postgres=# create trigger tg1 before insert on digoal for each statement execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg2 before insert on digoal for each row execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg3 after insert on digoal for each row execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg4 after insert on digoal for each statement execute procedure debug(); CREATE TRIGGER -- 创建多个同类型的触发器 postgres=# create trigger tg01 before insert on digoal for each statement execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg02 before insert on digoal for each row execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg03 after insert on digoal for each row execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg04 after insert on digoal for each statement execute procedure debug(); CREATE TRIGGER -- 插入测试 : postgres=# insert into digoal values (1); NOTICE: 00000: tg01 -- 第1被触发的是tg01, before for each statement, 同类触发器tg01按字母顺序排在tg1的前面. LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg1 -- 第2被触发的是tg1, before for each statement LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg02 -- 第3被触发的是tg02, before for each row, 同类触发器tg02按字母顺序排在tg2的前面. LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg2 -- 第4被触发的是tg2, before for each row LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg03 -- 第5被触发的是tg03, after for each row, 同类触发器tg03按字母顺序排在tg3的前面. LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg3 -- 第6被触发的是tg3, after for each row LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg04 -- 第7被触发的是tg04, after for each statement, 同类触发器tg04按字母顺序排在tg4的前面. LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg4 -- 第8被触发的是tg4, after for each statement LOCATION: exec_stmt_raise, pl_exec.c:2840 INSERT 0 1 -- 视图举例 -- 创建测试视图 postgres=# create view v_digoal as select * from digoal; CREATE VIEW -- 创建触发器 postgres=# create trigger tg1 before insert on v_digoal for each statement execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg2 instead of insert on v_digoal for each row execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg3 after insert on v_digoal for each statement execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg01 before insert on v_digoal for each statement execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg02 instead of insert on v_digoal for each row execute procedure debug(); CREATE TRIGGER postgres=# create trigger tg03 after insert on v_digoal for each statement execute procedure debug(); CREATE TRIGGER -- 测试 postgres=# insert into v_digoal values (2); NOTICE: 00000: tg01 -- 第1被触发的是tg01, before for each statement, 同类触发器tg01按字母顺序排在tg1的前面. LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg1 -- 第2被触发的是tg1, before for each statement LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg02 -- 第3被触发的是tg02, instead of for each row, 同类触发器tg02按字母顺序排在tg2的前面. LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg2 -- 第4被触发的是tg2, instead of for each row LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg03 -- 第5被触发的是tg03, after for each statement, 同类触发器tg03按字母顺序排在tg3的前面. LOCATION: exec_stmt_raise, pl_exec.c:2840 NOTICE: 00000: tg3 -- 第6被触发的是tg3, after for each statement LOCATION: exec_stmt_raise, pl_exec.c:2840 INSERT 0 1
同一个触发器函数可以被多个触发器调用吗? 触发器函数的返回类型是什么? 触发器函数的返回值是否会影响下一个触发器函数或者被操作的行的数据? NEW 或者OLD record修改后会带来什么影响? 哪些触发器函数的返回值没有意义?
– 同一个触发器函数可以多次被触发器调用, 上面的例子中表和视图的14个触发器中都是调用的debug()触发器函数.
– 触发器函数的返回值为空 或者是 表或视图对应的record类型.
返回值举例 :
– 表触发器返回空测试
– 创建测试表
postgres=# create table t_ret (id int, info text, crt_time timestamp);
CREATE TABLE
– 创建触发器函数, 返回空.
postgres=# create or replace function tg_t_ret() returns trigger as
– 把before for each row的触发器删掉, 再测试插入 :
postgres=# drop trigger tg02 on t_ret;
DROP TRIGGER
postgres=# drop trigger tg2 on t_ret;
DROP TRIGGER
postgres=# insert into t_ret values(1,’digoal’,now());
NOTICE: 00000: tg01
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg1
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg03, after for each row 的触发器函数返回空, 不影响后续的触发器是否被调用.
因为只要表上面发生了真正的行操作, after for each row就会被触发, 除非when条件不满足. (这个后面会讲到)
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg3
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg04
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg4
LOCATION: exec_stmt_raise, pl_exec.c:2840
INSERT 0 1
– 有数据插入. 这也说明了before for each statement的返回值为空并不会影响数据库对行的操作. 只有before for each row的返回值会影响数据库对行的操作.
postgres=# select * from t_ret ;
id | info | crt_time
—-+——–+—————————-
1 | digoal | 2013-03-10 16:50:39.551481
(1 row)
– 针对上例, 对tg03触发器的触发加一个when条件.
postgres=# drop trigger tg03 on t_ret;
DROP TRIGGER
– 只有当表的行数据真正受到影响时, after for each row 触发器才会被触发, 加了when条件后, 则还需要判断这个条件.
postgres=# create trigger tg03 after insert on t_ret for each row when (new.info is not null) execute procedure tg_t_ret();
CREATE TRIGGER
– 因为new.info 为空, 不满足WHEN条件, 所以tg03没有被触发.
postgres=# insert into t_ret values(1,null,now());
NOTICE: 00000: tg01
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg1
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg3
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg04
LOCATION: exec_stmt_raise, pl_exec.c:2840
NOTICE: 00000: tg4
LOCATION: exec_stmt_raise, pl_exec.c:2840
INSERT 0 1
– 表触发器返回record测试, NEW 或者OLD record修改后会带来什么影响?
– 前面的例子已经知道, for each statement的返回值对行的值以及for each row的触发器没有影响. 所以下面的例子都是针对for each row的.
INSERT before for each row 触发器函数 接收 NEW, 修改这个record对结果的影响是什么?
– 创建测试表
postgres=# drop table t_ret ;
DROP TABLE
postgres=# create table t_ret(id int, info text, crt_time timestamp);
CREATE TABLE
– 创建触发器函数, 修改NEW并返回.
postgres=# create or replace function tg_t_ret() returns trigger as
– 用这个触发器函数, 更能看出多个触发器函数以及对行数据操作时使用的是触发器函数的返回值, 而不是NEW变量本身.
postgres=# \d t_ret
Table “public.t_ret”
Column | Type | Modifiers
———-+—————————–+———–
id | integer |
info | text |
crt_time | timestamp without time zone |
Triggers:
tg01 BEFORE INSERT ON t_ret FOR EACH ROW EXECUTE PROCEDURE tg_t_ret()
tg02 AFTER INSERT ON t_ret FOR EACH ROW EXECUTE PROCEDURE tg_t_ret()
tg1 BEFORE INSERT ON t_ret FOR EACH ROW EXECUTE PROCEDURE tg_t_ret()
tg2 AFTER INSERT ON t_ret FOR EACH ROW EXECUTE PROCEDURE tg_t_ret()– 触发器函数如下 :
postgres=# create or replace function tg_t_ret() returns trigger as
– 使用这个函数更能观察出after for each row触发器函数的返回值并不影响下一个after for each row的NEW变量.
– 因为after for each row 的触发器函数中NEW值(统一来自真正被影响的行数据)
– 修改触发器函数 :
postgres=# create or replace function tg_t_ret() returns trigger as
125
(1 row)
INSERT 0 1
– DELETE before for each row 触发器函数 接收 OLD, 修改这个record对结果的影响是什么?
postgres=# create or replace function tg_t_ret() returns trigger as
– UPDATE before for each row 触发器函数 接收 NEW 还是 OLD? 修改这个record对结果的影响是什么?
postgres=# drop table t_ret;
DROP TABLE
postgres=# create table t_ret(id int, info text, crt_time timestamp);
CREATE TABLE
postgres=# insert into t_ret values (1,’digoal’,now()), (2,’DIGOAL’,now()), (3,’digoal’,now()), (4,’abc’,now());
INSERT 0 4
postgres=# create or replace function tg_t_ret() returns trigger as
– 当update before for each row 触发器函数的返回值不为空时, 被更改的行的最终值将与最后一个执行的before for each row 触发器函数的返回值一致.
– 本例的tg2是最后一次调用的update before for each row触发器函数, 它的返回值为NEW.id := 3, NEW.info := ‘new’, NEW.crt_time保持原值.
– 因此更新后的值id = 3, 而不是原来的1.
postgres=# create or replace function tg_t_ret() returns trigger as
– 返回的record必须与触发这个触发器的表的结构一致. 否则无法转换成该tuple结构. 报错.
postgres=# create or replace function tg_t_ret() returns trigger as
– 视图触发器返回空测试
– 创建基表
digoal=> create table tbl (id int, info text, crt_time timestamp);
CREATE TABLE
– 创建视图
digoal=> create view v_tbl as select * from tbl;
CREATE VIEW
– 创建触发器函数
digoal=> create or replace function tg() returns trigger as
– 视图触发器返回record测试, NEW 或者OLD record修改后会带来什么影响?
– 创建触发器函数
digoal=> create or replace function tg() returns trigger as
– 需要注意OLD的修改不会传递给下一个instead for each row触发器函数, 也不会传递给操作行的C函数, 也不会传递给returning.
– 基表数据插入
digoal=> insert into tbl values (1, ‘digoal’, now());
INSERT 0 1
– 基表数据
digoal=> select * from tbl;
id | info | crt_time
—-+——–+—————————-
1 | digoal | 2013-03-11 08:56:20.326402
(1 row)
– 删除操作, 触发器函数的返回值为OLD. 但是显然没有传递给下一个触发器函数的OLD变量.
– 因为两次修改后的OLD.id都是2, 如果传递过去的话, 第二次修改后的OLD.id应该是3
digoal=> delete from v_tbl where id=1 returning *;
NOTICE: DELETE, tg0, INSTEAD OF, ROW, old:(2,digoal,”2013-03-11 08:56:20.326402”)
NOTICE: DELETE, tg1, INSTEAD OF, ROW, old:(2,digoal,”2013-03-11 08:56:20.326402”)
id | info | crt_time
—-+——–+—————————-
1 | digoal | 2013-03-11 08:56:20.326402
(1 row)
DELETE 1
– 因为返回值不为空, 所以row_count变量增1, 同时returning的值来自真实的行数据. 而不是OLD的值.
digoal=> select * from tbl;
id | info | crt_time
—-+——–+—————————-
1 | digoal | 2013-03-11 08:56:20.326402
(1 row)
– 因为id=2不存在, 所以不会触发instead of for each row触发器.
digoal=> delete from v_tbl where id=2 returning *;
id | info | crt_time
—-+——+———-
(0 rows)
DELETE 0
– 以上触发器函数修改一下, 可以实现修改视图, 并且想修改表一样可以正常返回ROW_COUNT和RETURNING.
create or replace function tg() returns trigger as
【小结2】
1. 给视图触发器函数添加返回值, 可以令视图的DML操作和操作表一样正常返回ROW_COUNT和RETURNING值.
2. 当一个视图上创建了多个instead of for each row触发器时, 触发器函数的返回值将传递给下一个被调用的instead of for each row触发器函数的NEW变量, (OLD不传递).
【小结3】
1. 哪些触发器函数的返回值没有意义?
– for each statement的触发器函数的返回值没有意义, 不会造成任何影响. 不管是返回NULL还是HeapTuple都无意义, 所以返回NULL就可以了.
– after for each row 的触发器函数的返回值也没有意义, 不会造成任何影响. 不管是返回NULL还是HeapTuple都无意义, 所以返回NULL就可以了.
– 因此有意义的就是before for each row的触发器函数的返回值.
– before for each row触发器函数返回NULL将造成跳过该行的操作, 同时跳过后面所有的for each row触发器.
– before for each row触发器函数返回HeapTuple时, 返回值将传递给下一个before for each row的触发器函数的NEW, 或者行操作的C函数.
– 注意OLD不会传递给下一个触发器函数或操作行的C函数.
GET [ CURRENT ] DIAGNOSTICS variable = item [ , … ];
This command allows retrieval of system status indicators. Each item is a key word identifying a status value to be assigned to the specified variable (which should be of the right data type to receive it). The currently available status items are ROW_COUNT, the number of rows processed by the last SQL command sent to the SQL engine, and RESULT_OID, the OID of the last row inserted by the most recent SQL command. Note that RESULT_OID is only useful after an INSERT command into a table containing OIDs.
An example:
GET DIAGNOSTICS integer_var = ROW_COUNT;
The second method to determine the effects of a command is to check the special variable named FOUND, which is of type boolean. FOUND starts out false within each PL/pgSQLfunction call. It is set by each of the following types of statements:
A SELECT INTO statement sets FOUND true if a row is assigned, false if no row is returned.
A PERFORM statement sets FOUND true if it produces (and discards) one or more rows, false if no row is produced.
UPDATE, INSERT, and DELETE statements set FOUND true if at least one row is affected, false if no row is affected.
A FETCH statement sets FOUND true if it returns a row, false if no row is returned.
A MOVE statement sets FOUND true if it successfully repositions the cursor, false otherwise.
A FOR or FOREACH statement sets FOUND true if it iterates one or more times, else false. FOUND is set this way when the loop exits; inside the execution of the loop, FOUND is not modified by the loop statement, although it might be changed by the execution of other statements within the loop body.
RETURN QUERY and RETURN QUERY EXECUTE statements set FOUND true if the query returns at least one row, false if no row is returned.
Other PL/pgSQL statements do not change the state of FOUND. Note in particular that EXECUTE changes the output of GET DIAGNOSTICS, but does not change FOUND.
FOUND is a local variable within each PL/pgSQL function; any changes to it affect only the current function.
参见 :
http://www.postgresql.org/docs/9.2/static/plpgsql-statements.html
Note that for constraint triggers, evaluation of the WHEN condition is not deferred, but occurs immediately after the row update operation is performed. If the condition does not evaluate to true then the trigger is not queued for deferred execution.
触发器还有一个和会话参数session_replication_role结合使用的隐含特性, 需要使用ALTER TABLE来修改, 如下 :
session_replication_role (enum)
Controls firing of replication-related triggers and rules for the current session. Setting this variable requires superuser privilege and results in discarding any previously cached query plans.
Possible values are origin (the default), replica and local.
See ALTER TABLE for more information.
DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER
These forms configure the firing of trigger(s) belonging to the table. A disabled trigger is still known to the system, but is not executed when its triggering event occurs. For a deferred trigger, the enable status is checked when the event occurs, not when the trigger function is actually executed.
One can disable or enable a single trigger specified by name, or all triggers on the table, or only user triggers (this option excludes internally generated constraint triggers such as those that are used to implement foreign key constraints or deferrable uniqueness and exclusion constraints).
Disabling or enabling internally generated constraint triggers requires superuser privileges; it should be done with caution since of course the integrity of the constraint cannot be guaranteed if the triggers are not executed.
The trigger firing mechanism is also affected by the configuration variable session_replication_role.
Simply enabled triggers will fire when the replication role is “origin” (the default) or “local”.
Triggers configured as ENABLE REPLICA will only fire if the session is in “replica” mode, and triggers configured as ENABLE ALWAYS will fire regardless of the current replication mode.
如果在表上面执行enable replica trigger tgname,那么这个触发器只有当会话参数sessionreplicationrole=replica时,才会被触发.如果会话参数sessionreplicationrole=origin或者local,这个触发器将不会被触发.如果在表上面执行enablealwaystrigger tg_name, 那么这个触发器不管会话参数session_replication_role的值是什么, 都会被触发.
其实这个用法还可以通过application_name参数以及触发器中配置判断application_name的控制语句来实现, 当然效率没有上面的方法高 :
例如 :
pgsql中的application_name可以这么来修改 :
– 连接参数中修改
ocz@db-172-16-3-150-> psql postgresql://:9201/digoal?application_name=digoal
psql (9.2.1)
Type “help” for help.
digoal=# show application_name;
digoal
(1 row)
digoal=# \q
– 会话中修改 :
ocz@db-172-16-3-150-> psql
psql (9.2.1)
Type “help” for help.
postgres=# show application_name;
psql
(1 row)
postgres=# set application_name=’abc’;
SET
postgres=# show application_name;
abc
(1 row)
使用application_name实现触发器内部控制 :
digoal=> create table abc(id int, info text);
CREATE TABLE
digoal=> create or replace function tg() returns trigger as
psql
(1 row)
digoal=> insert into abc values(1,’digoal’);
INSERT 0 1
– 当application_name=’digoal’时不插入数据.
digoal=> set application_name=’digoal’;
SET
digoal=> insert into abc values(1,’digoal’);
INSERT 0 0
使用session_replication_role来控制触发器是否被触发.
digoal=> create table abc(id int, info text);
CREATE TABLE
digoal=> create or replace function tg() returns trigger as
origin
(1 row)
digoal=> insert into abc values (1,’digoal’);
INSERT 0 1
– set session_replication_role需要超级用户权限 :
digoal=> \c digoal postgres
You are now connected to database “digoal” as user “postgres”.
– 当session_replication_role=replica并且trigger tg0 修改为enable replica时, 触发器被触发了.
digoal=# set session_replication_role=’replica’;
SET
digoal=# insert into digoal.abc values (1,’digoal’);
NOTICE: tg0
INSERT 0 1
【小结】
1. 注意各种触发器在操作流中的顺序, 返回值的传递, 返回值的意义.
2. 注意当1个表上有多个同类触发器时, 需要注意他们之间的参数传递, 触发顺序.
3. 还要注意触发器的可视, 下一篇中会着重讲可视特性.
【参考】
1. http://www.postgresql.org/docs/9.2/static/trigger-definition.html
2. http://www.postgresql.org/docs/9.2/static/trigger-datachanges.html
3. http://www.postgresql.org/docs/9.2/static/spi-visibility.html
4. http://www.postgresql.org/docs/9.2/static/trigger-example.html
5. http://www.postgresql.org/docs/9.2/static/plpgsql-trigger.html
6. http://www.postgresql.org/docs/9.2/static/sql-createtrigger.html
7. http://www.postgresql.org/docs/9.2/static/trigger-interface.html
8. http://www.postgresql.org/docs/9.2/static/sql-set-constraints.html
9. src/backend/commands/trigger.c
10. src/include/commands/trigger.h
11. src/include/utils/reltrigger.h
12. 触发器的应用 :
http://blog.163.com/digoal@126/blog/static/16387704020128772037884/
http://blog.163.com/digoal@126/blog/static/16387704020120133019990/
http://blog.163.com/digoal@126/blog/static/163877040201251931517556/
http://blog.163.com/digoal@126/blog/static/16387704020130931040444/
http://blog.163.com/digoal@126/blog/static/163877040201301483549300/
http://blog.163.com/digoal@126/blog/static/1638770402012325111528424/
http://blog.163.com/digoal@126/blog/static/163877040201211193542316/
http://blog.163.com/digoal@126/blog/static/1638770402012731203716/
http://blog.163.com/digoal@126/blog/static/1638770402012731944439/
http://blog.163.com/digoal@126/blog/static/16387704020128142829610/
http://blog.163.com/digoal@126/blog/static/16387704020129851138327/
http://blog.163.com/digoal@126/blog/static/163877040201119111234570/
https://yq.aliyun.com/articles/2261
“`