触发器是一种由事件自动触发执行的特殊的存储过程,这些事件可以是对一个表进行的INSERT、UPDATE、DELETE等。
触发器经常用于加强数的完整性约束和业务规则上的约束等。
创建语法:
CREATE [ CONSTRAINT ] TRIGGER name { BEFORE | AFTER | INSTEAD OF } { event [ OR ... ] }
ON table_name
[ FROM referenced_table_name ]
[ NOT DEFERRABLE | [ DEFERRABLE ] [ INITIALLY IMMEDIATE | INITIALLY DEFERRED ] ]
[ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name } [ ... ] ]
[ FOR [ EACH ] { ROW | STATEMENT } ]
[ WHEN ( condition ) ]
EXECUTE { FUNCTION | PROCEDURE } function_name ( arguments )
触发事件包括以下几种:
INSERT-插入
UPDATE [ OF column_name [, ... ] ]-更新
DELETE-删除
TRUNCATE-清除
PS:
不同于Oracle的触发器将触发后的操作定义在触发器本身的语法中,Postgresql的触发器是在触发后执行指定的函数(function)或者存储过程(procedure),触发的操作就是执行函数或存储过程。
创建触发器的步骤:
先为触发器创建一个执行函数,此函数返回的类型为触发器类型,然后即可创建相应的触发器。
例如:
create table student(
student_no int primary key,
student_name varchar(90),
age int,
sex boolean
);
create table score(
student_no int,
chinese_score int,
math_score int,
test_date date
);
如果在删除学生表中的一条记录时,对应这个学生的成绩表中的记录也会被删除,先创建触发器的触发函数:
create or replace function student_delete_trigger()
returns trigger as $$
begin
delete from score where student_no=OLD.student_no;
return old;
end;
$$ language plpgsql;
然后依据创建的触发函数创建对应的触发器:
create trigger delete_student_trigger
after delete on student
for each row execute procedure student_delete_trigger();
插入测试数据:
insert into student values(1,'张三',15);
insert into student values(2,'赵四',13);
insert into student values(3,'王二',16);
insert into student values(4,'李六',14);
insert into student values(5,'周康',18);
insert into student values(6,'丽丽',12);
insert into score values(1,88,79, date '2020-05-08');
insert into score values(1,80,91, date '2020-11-13');
insert into score values(2,81,88, date '2020-05-08');
insert into score values(2,90,90, date '2020-11-13');
insert into score values(3,89,82, date '2020-05-08');
insert into score values(3,91,78, date '2020-11-13');
insert into score values(4,90,77, date '2020-05-08');
insert into score values(4,87,79, date '2020-11-13');
insert into score values(5,82,92, date '2020-05-08');
insert into score values(5,84,95, date '2020-11-13');
insert into score values(6,79,94, date '2020-05-08');
insert into score values(6,86,86, date '2020-11-13');
数据如下:
postgres=# select * from student;
student_no | student_name | age | sex
------------+--------------+-----+-----
1 | 张三 | 15 |
2 | 赵四 | 13 |
3 | 王二 | 16 |
4 | 李六 | 14 |
5 | 周康 | 18 |
6 | 丽丽 | 12 |
(6 rows)
postgres=# select * from score;
student_no | chinese_score | math_score | test_date
------------+---------------+------------+------------
1 | 88 | 79 | 2020-05-08
1 | 80 | 91 | 2020-11-13
2 | 81 | 88 | 2020-05-08
2 | 90 | 90 | 2020-11-13
3 | 89 | 82 | 2020-05-08
3 | 91 | 78 | 2020-11-13
4 | 90 | 77 | 2020-05-08
4 | 87 | 79 | 2020-11-13
5 | 82 | 92 | 2020-05-08
5 | 84 | 95 | 2020-11-13
6 | 79 | 94 | 2020-05-08
6 | 86 | 86 | 2020-11-13
(12 rows)
现在删除学号为3的学生“王二”:
postgres=# delete from student where student_no=3;
DELETE 1
postgres=# select * from student;
student_no | student_name | age | sex
------------+--------------+-----+-----
1 | 张三 | 15 |
2 | 赵四 | 13 |
4 | 李六 | 14 |
5 | 周康 | 18 |
6 | 丽丽 | 12 |
(5 rows)
postgres=# select * from score;
student_no | chinese_score | math_score | test_date
------------+---------------+------------+------------
1 | 88 | 79 | 2020-05-08
1 | 80 | 91 | 2020-11-13
2 | 81 | 88 | 2020-05-08
2 | 90 | 90 | 2020-11-13
4 | 90 | 77 | 2020-05-08
4 | 87 | 79 | 2020-11-13
5 | 82 | 92 | 2020-05-08
5 | 84 | 95 | 2020-11-13
6 | 79 | 94 | 2020-05-08
6 | 86 | 86 | 2020-11-13
(10 rows)
以上测试看出,在删除学生“王二”后,对应score表中的记录也被删除。
语句级触发器时指执行每个SQL语句时,只执行一次,行级触发器则是指每行记录都会执行一次,一个修改0行的操作仍热会导致合适的语句级触发器被执行,
假设对表student的更新情况加上记录日志:
# 创建记录student表更新的日志表log_student
create table log_student(
update_time timestamp, --操作的时间
db_user varchar(60), --操作数据库用户名
opr_type varchar(12) --操作类型:insert、delete、update
);
创建记录log的触发器函数,如下:
create function log_student_trigger()
returns trigger as $$
begin
insert into log_student values(now(),user,TG_OP);
return null;
end;
$$ language plpgsql;
PS:创建语句中的 “TG_OP” 是触发器函数中的特殊变量,代表DML操作类型。
然后在表student上创建一个语句级触发器:
create trigger log_student_trigger
after insert or delete or update on student
for statement execute procedure log_student_trigger();
现在插入表student中两条记录(原先插入的可以先进行删除,是测试数据更清晰明了):
postgres=# insert into student values(7,'孙七',20),(8,'吴用',19);
INSERT 0 2
postgres=# select * from log_student;
update_time | db_user | opr_type
----------------------------+----------+----------
2020-03-11 14:30:22.714301 | postgres | INSERT
(1 row)
postgres=# select * from student;
student_no | student_name | age | sex
------------+--------------+-----+-----
7 | 孙七 | 20 |
8 | 吴用 | 19 |
(7 rows)
从上面可以看出,虽然是插入了两条记录,但是由于执行语句只有一条,所以在日志表log_student中只记录了一次操作。
现在将log_student中记录删除,然后更新表student中的记录:
postgres=# delete from log_student ;
DELETE 1
postgres=# update student set age=16;
UPDATE 2
postgres=# select * from log_student ;
update_time | db_user | opr_type
----------------------------+----------+----------
2020-03-11 14:35:19.804496 | postgres | UPDATE
(1 row)
从上面看到,虽然一条update语句更新了两行记录,但是在log_student中只记录了一行记录,说明了语句级触发器是按照语句进行触发的,不管这条语句实际操作了多少行记录。
但是语句级触发器更新0行时,也就是更新条件没有记录,但实际也会触发语句级触发器进行一次操作:
postgres=# delete from log_student ;
DELETE 1
postgres=# update student set age=20 where age=10;
UPDATE 0
postgres=# select * from log_student ;
update_time | db_user | opr_type
----------------------------+----------+----------
2020-03-11 14:38:16.104763 | postgres | UPDATE
(1 row)
删除student的语句级触发器,清空log_student中的操作日记记录:
postgres=# drop trigger log_student_trigger on student;
DROP TRIGGER
postgres=# delete from log_student ;
DELETE 1
postgres=# delete from student;
DELETE 2
在student表上创建行级触发器:
create trigger log_student_trigger2
after insert or delete or update on student
for row execute procedure log_student_trigger();
然后使用一条SQL语句插入两条记录,如下:
postgres=# insert into student values(1,'李四',20),(2,'张三',19);
INSERT 0 2
postgres=# select * from log_student ;
update_time | db_user | opr_type
----------------------------+----------+----------
2020-03-11 14:43:37.901749 | postgres | INSERT
2020-03-11 14:43:37.901749 | postgres | INSERT
(2 rows)
postgres=# select * from student;
student_no | student_name | age | sex
------------+--------------+-----+-----
1 | 李四 | 20 |
2 | 张三 | 19 |
(2 rows)
从上面看出一条SQL语句插入两条记录后在log_student表中也会记录两条日志记录。
尝试执行一次更新操作:
postgres=# delete from log_student ;
DELETE 2
postgres=# update student set age=16;
UPDATE 2
postgres=# select * from log_student ;
update_time | db_user | opr_type
----------------------------+----------+----------
2020-03-11 14:45:42.426286 | postgres | UPDATE
2020-03-11 14:45:42.426286 | postgres | UPDATE
(2 rows)
更新操作同样会在log_student表中记录两条日志记录。
但是与语句级触发器不同,行级触发器如果更新操作没有修改任何行,则不会触发行级触发器,例如:
postgres=# delete from log_student ;
DELETE 2
postgres=# update student set age=20 where age=10;
UPDATE 0
postgres=# select * from log_student ;
update_time | db_user | opr_type
-------------+---------+----------
(0 rows)
一般,语句级别的 “before” 触发器是在语句开始做任何事情之前就被触发了的,而语句级别的 “after” 触发器是在语句结束时才触发的,行级别的 “before” 触发器在对特定行进行操作前触发,而行级别的 “after” 触发器是在语句结束时才触发的,但是它会在任何语句级别的 “after” 触发器被触发之前触发。
before 触发器可以直接修改 “NEW” 值以改变实际的更新值,例如:
# 触发器依赖函数
create function student_user_new_name_trigger()
returns trigger as $$
begin
NEW.student_name = NEW.student_name||NEW.student_no;
return NEW;
end;
$$ language plpgsql;
# 触发器
create trigger user_name_student_trigger
before insert or update on student
for each row execute procedure student_user_new_name_trigger();
这个函数的作用就是在插入表student或者更新时,在插入值的 “student_name” 名称后加上 “student_no”,作为新的 student_name 插入表student的列中。
例如:
postgres=# select * from student;
student_no | student_name | age | sex
------------+--------------+-----+-----
1 | 李四 | 16 |
2 | 张三 | 16 |
(2 rows)
postgres=# insert into student values(3,'王二',19);
INSERT 0 1
postgres=# select * from student;
student_no | student_name | age | sex
------------+--------------+-----+-----
1 | 李四 | 16 |
2 | 张三 | 16 |
3 | 王二3 | 19 |
(3 rows)
相对的,如果创建的触发器时 AFTER,则修改NEW时没有用的。
语法:
DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
语法说明:
1.IF EXISTS:如果指定的触发器不存在,返回一个notice,不会抛出错误。
2.CASCADE:级联删除依赖此触发器的对象。
3.RESTRICT:默认值,如果依赖的对象不存在,那么拒绝删除。
例如:
DROP TRIGGER user_name_student_trigger ON student;
PS: 删除触发器时,触发器的函数不会删除;删除表的时候,表上的触发器会删除。
触发器函数有返回值。
语句级触发器应该总是返回NULL,即必须显式地在触发器函数中协商 “RETURN NULL” ,如果没有写,将导致出错,例如:
# 创建触发器函数,并且没有返回null
create or replace function log_student_triger()
returns trigger as $$
begin
insert into log_student values(now(),user,TG_OP);
end;
$$ language plpgsql;
# 创建语句级触发器
create trigger log_student_trigger
after insert or delete or update on student
for statement execute procedure log_student_triger();
对表插入测试数据时就会出现如下错误:
postgres=# insert into student values(4,'zhang',20);
ERROR: control reached end of trigger procedure without RETURN
CONTEXT: PL/pgSQL function log_student_triger()
对于 before 和 instead of 这类行级触发器来说,如果返回的是 NULL,则表示忽略对当前行的操作。如果是返回非 NULL 的行,对于 insert 和 update 操作来说,返回的行将成为被插入的行或者更新的行。
对于 after 这类行级触发器来说,其返回值会被忽略。
如果同一事物上有多个触发器,则将按触发器名字的顺序来触发。如果是 before 和 instead of 行级触发器,每个触发器返回的行(可能已被更改)将成为下一个触发器的输入。如果 before 和 instead of 行级触发器返回的内容为空,那么该行上的其他行级触发器也不会被触发。
当把一个 PL/pgsql函数当作触发器函数调用的时候,系统会在顶层的声明段里自动创建几个特殊变量,比如之前看到的 “OLD”、“NEW”、“TG_OP”变量等。
特殊变量主要有以下几种:
1.NEW:
该变量为 insert/update 操作触发的行级触发器中存储的新的数据行,数据类型是 “RECORD” ,在语句级别的触发器里此变量没有分配,delete 操作触发的行级触发器中此变量也没有分配。
2.OLD:
该变量为 update/delete 操作触发的行级触发器中存储的旧数据行,数据类型为 “RECORD”,在语句级别的触发器里此变量没有分配,insert 操作触发的行级触发器中此变量也没有分配。
3.TG_NAME:
数据类型为 name,该变量包含实际触发的触发器名称。
4.TG_WHEN:
内容为 “BEFORE” 或 “AFTER” 的字符串用于指定是BEFORE触发还是AFTER触发。
5.TG_LEVEL:
内容为 “ROW” 或 “STATEMENT” 的字符串用于指定是语句级触发器还是行级触发器。
6.TG_OP:
内容为 “INSERT”、“UPDATE”、“DELETE”、“TRUNCATE”之一的字符串,用于指定DML语句的类型。
7.TG_RELID:
触发器所在的表的OID。
8.RELNAME:
触发器所在表的名称,这个变量即将废弃,被 TG_TABLE_NAME 变量所替代。
9.TG_TABLE_NAME:
触发器所在的表的名称。
10.TG_TABLE_SCHEMA:
触发器所在表的模式名称。
11.TG_NARGS:
在 CREATE TRIGGER 语句里面赋予触发器过程的参数个数。
12.TG_ARGV[]:
为text类型的一个数组;是 CREATE TRIGGER 语句里的参数。
Postgresql从9.3开始支持事件触发器(event trigger),这种触发器使得Postgresql支持DDL触发,目前事件触发器支持以下三种DDL事件:
1.ddl_command_start:一个DDL开始执行前被触发。
2.ddl_command_end:一个DDL执行完成后被触发。
3.sql_drop:删除一个数据库对象前被触发。
由于事件触发器涉及的权限比较大,所以只有超级用户才能创建和修改事件触发器。
各种DDL操作会触发的事件如下:
command tag | ddl_command_start | ddl_command_end | sql_drop |
---|---|---|---|
ALTER AGGREGATE | X | X | - |
ALTER COLLATION | X | X | - |
ALTER CONVERSION | X | X | - |
ALTER DOMAIN | X | X | - |
ALTER EXTENSION | X | X | - |
ALTER FOREIGN DATA WRAPPER | X | X | - |
ALTER FOREIGN TABLE | X | X | X |
ALTER FUNCTION | X | X | - |
ALTER LANGUAGE | X | X | - |
ALTER OPERATOR | X | X | - |
ALTER OPERATOR CLASS | X | X | - |
ALTER OPERATOR FAMILY | X | X | - |
ALTER SCHEMA | X | X | - |
ALTER SEQUENCE | X | X | - |
ALTER SERVER | X | X | - |
ALTER TABLE | X | X | X |
ALTER TEXT SEARCH CONFIGURATION | X | X | - |
ALTER TEXT SEARCH DICTIONARY | X | X | - |
ALTER TEXT SEARCH PARSER | X | X | - |
ALTER TEXT SEARCH TEMPLATE | X | X | - |
ALTER TRIGGER | X | X | - |
ALTER TYPE | X | X | - |
ALTER USER MAPPING | X | X | - |
ALTER VIEW | X | X | - |
CREATE AGGREGATE | X | X | - |
CREATE CAST | X | X | - |
CREATE COLLATION | X | X | - |
CREATE CONVERSION | X | X | - |
CREATE DOMAIN | X | X | - |
CREATE EXTENSION | X | X | - |
CREATE FOREIGN DATA WRAPPER | X | X | - |
CREATE FOREIGN TABLE | X | X | - |
CREATE FUNCTION | X | X | - |
CREATE INDEX | X | X | - |
CREATE LANGUAGE | X | X | - |
CREATE OPERATOR | X | X | - |
CREATE OPERATOR CLASS | X | X | - |
CREATE OPERATOR FAMILY | X | X | - |
CREATE RULE | X | X | - |
CREATE SCHEMA | X | X | - |
CREATE SEQUENCE | X | X | - |
CREATE SERVER | X | X | - |
CREATE TABLE | X | X | - |
CREATE TABLE AS | X | X | - |
CREATE TEXT SEARCH CONFIGURATION | X | X | - |
CREATE TEXT SEARCH DICTIONARY | X | X | - |
CREATE TEXT SEARCH PARSER | X | X | - |
CREATE TEXT SEARCH TEMPLATE | X | X | - |
CREATE TRIGGER | X | X | - |
CREATE TYPE | X | X | - |
CREATE USER MAPPING | X | X | - |
CREATE VIEW | X | X | - |
DROP AGGREGATE | X | X | X |
DROP CAST | X | X | X |
DROP COLLATION | X | X | X |
DROP CONVERSION | X | X | X |
DROP DOMAIN | X | X | X |
DROP EXTENSION | X | X | X |
DROP FOREIGN DATA WRAPPER | X | X | X |
DROP FOREIGN TABLE | X | X | X |
DROP FUNCTION | X | X | X |
DROP INDEX | X | X | X |
DROP LANGUAGE | X | X | X |
DROP OPERATOR | X | X | X |
DROP OPERATOR CLASS | X | X | X |
DROP OPERATOR FAMILY | X | X | X |
DROP OWNED | X | X | X |
DROP RULE | X | X | X |
DROP SCHEMA | X | X | X |
DROP SEQUENCE | X | X | X |
DROP SERVER | X | X | X |
DROP TABLE | X | X | X |
DROP TEXT SEARCH CONFIGURATION | X | X | X |
DROP TEXT SEARCH DICTIONARY | X | X | X |
DROP TEXT SEARCH PARSER | X | X | X |
DROP TEXT SEARCH TEMPLATE | X | X | X |
DROP TRIGGER | X | X | X |
DROP TYPE | X | X | X |
DROP USER MAPPING | X | X | X |
DROP VIEW | X | X | X |
SELECT INTO | X | X | - |
语法:
CREATE EVENT TRIGGER name
ON event
[ WHEN filter_variable IN (filter_value [, ... ]) [ AND ... ] ]
EXECUTE { FUNCTION | PROCEDURE } function_name()
在创建事件触发器前,必须先创建触发器函数,事件触发器函数的返回类型与普通触发器的返回类型不一样,它返回的类型为 event_trigger。
官方文档提供的禁止数据库所有DDL操作的触发器:
CREATE OR REPLACE FUNCTION abort_any_command()
RETURNS event_trigger
LANGUAGE plpgsql
AS $$
BEGIN
RAISE EXCEPTION 'command % is disabled', tg_tag;
END;
$$;
CREATE EVENT TRIGGER abort_ddl ON ddl_command_start
EXECUTE FUNCTION abort_any_command();
触发器创建完成后,在数据库中删除一张表就会出现报错:
postgres=# drop table tb_test03;
ERROR: command DROP TABLE is disabled
CONTEXT: PL/pgSQL function abort_any_command() line 3 at RAISE
postgres=# create table tb_drop_opr(id int);
ERROR: command CREATE TABLE is disabled
CONTEXT: PL/pgSQL function abort_any_command() line 3 at RAISE
但是需要注意的是,truncate table 的操作还是可以执行的,因为在Postgresql‘中 truncate 事件使用普通的触发器触发,事件触发器不会触发 truncate table 操作。
另外事件触发器本省是不会触发事件操作器的。
如果你像再允许数据库进行DDL操作,可以禁止掉事件触发器,命令如下:
postgres=# alter event trigger abort_ddl disable;
ALTER EVENT TRIGGER
postgres=# create table tb_drop_opr(id int);
CREATE TABLE
在Postgresql的9.3版本中,事件触发器函数中仅仅支持TG_EVENT和TG_TAG两个变量。
1.TG_EVENT:为 “ddl_command_start”、“ddl_command_end”、“sql_drop”之一。
2.TG_TAG:指具体的那种DDL操作,如 ”CREATE TABLE"、“DROP TABLE”等。
所以在9.x版本中DDL操作还不太清楚的显示操作了什么数据库对象。
对于 ”sql_drop“ 事件触发器中函数,可以调用一个函数:pg_event_trigger_dropped_objects(),以获取删除数据库对象的信息,这个函数会返回一个结果集,包括如下信息:
列名称 | 列类型 | 列说明 |
---|---|---|
classid | Oid | 数据库对象的类型(catalog)的OID |
objid | Oid | 数据库对象的OID |
objsubid | int32 | 数据库对象的子对象(如列) |
object_type | text | 数据库对象的类型 |
schema_name | text | 数据对象的模式名称 |
object_name | text | 数据库对象的名称 |
object_identity | text | 数据库对象的标识符 |
在数据库中通过查询视图PG_EVENT_TRIGGER可以看到已有的事件触发器:
postgres=# select * from pg_event_trigger;
oid | evtname | evtevent | evtowner | evtfoid | evtenabled | evttags
-------+-----------+-------------------+----------+---------+------------+---------
16799 | abort_ddl | ddl_command_start | 10 | 16798 | D |
(1 row)
创建一个事件触发器,用于记录数据库中删除对象的审计日志:
# 创建存放删除审计日志的表
create table log_drop_objects(
op_time timestamp,
ddl_tag text,
classid oid,
objid oid,
objsubid oid,
object_type text,
schema_name text,
object_name text,
object_identity text);
# 创建事件触发器函数
create function event_trigger_log_drop()
returns event_trigger language plpgsql as $$
declare
obj record;
begin
insert into log_drop_objects select now(), tg_tag, classid, objid, objsubid, object_type, schema_name, object_name, object_identity from pg_event_trigger_dropped_objects();
end
$$;
# 创建事件触发器
create event trigger event_trigger_log_drop
on sql_drop
execute procedure event_trigger_log_drop();
创建测试表进行测试:
postgres=# drop table tb_drop_opr ;
DROP TABLE
postgres=# drop table tb_test03 ;
DROP TABLE
postgres=# drop table tb_test02 ;
DROP TABLE
postgres=# create table tb_drop_adit(id int,name text);
CREATE TABLE
postgres=# alter table tb_drop_adit drop column name;
ALTER TABLE
postgres=# select * from log_drop_objects ;
op_time | ddl_tag | classid | objid | objsubid | object_type | schema_name | object_name
| object_identity
----------------------------+-------------+---------+-------+----------+------------------+-------------+--------------------
--+-----------------------------------------
2020-03-12 11:05:38.564912 | DROP TABLE | 1259 | 16800 | 0 | table | public | tb_drop_opr
| public.tb_drop_opr
2020-03-12 11:05:38.564912 | DROP TABLE | 1247 | 16802 | 0 | type | public | tb_drop_opr
| public.tb_drop_opr
2020-03-12 11:05:38.564912 | DROP TABLE | 1247 | 16801 | 0 | type | public | _tb_drop_opr
| public.tb_drop_opr[]
2020-03-12 11:05:50.58055 | DROP TABLE | 1259 | 16608 | 0 | table | public | tb_test03
| public.tb_test03
2020-03-12 11:05:50.58055 | DROP TABLE | 1247 | 16610 | 0 | type | public | tb_test03
| public.tb_test03
2020-03-12 11:05:50.58055 | DROP TABLE | 1247 | 16609 | 0 | type | public | _tb_test03
| public.tb_test03[]
2020-03-12 11:05:50.58055 | DROP TABLE | 2606 | 16611 | 0 | table constraint | public |
| tb_test03_age_check on public.tb_test03
2020-03-12 11:05:50.58055 | DROP TABLE | 1259 | 16612 | 0 | toast table | pg_toast | pg_toast_16608
| pg_toast.pg_toast_16608
2020-03-12 11:05:50.58055 | DROP TABLE | 1247 | 16613 | 0 | type | pg_toast | pg_toast_16608
| pg_toast.pg_toast_16608
2020-03-12 11:05:50.58055 | DROP TABLE | 1259 | 16614 | 0 | index | pg_toast | pg_toast_16608_inde
x | pg_toast.pg_toast_16608_index
2020-03-12 11:05:50.58055 | DROP TABLE | 2606 | 16616 | 0 | table constraint | public |
| tb_test03_pkey on public.tb_test03
2020-03-12 11:05:50.58055 | DROP TABLE | 1259 | 16615 | 0 | index | public | tb_test03_pkey
| public.tb_test03_pkey
2020-03-12 11:05:54.308963 | DROP TABLE | 1259 | 16539 | 0 | table | public | tb_test02
| public.tb_test02
2020-03-12 11:05:54.308963 | DROP TABLE | 1247 | 16541 | 0 | type | public | tb_test02
| public.tb_test02
2020-03-12 11:05:54.308963 | DROP TABLE | 1247 | 16540 | 0 | type | public | _tb_test02
| public.tb_test02[]
2020-03-12 11:05:54.308963 | DROP TABLE | 1259 | 16542 | 0 | toast table | pg_toast | pg_toast_16539
| pg_toast.pg_toast_16539
2020-03-12 11:05:54.308963 | DROP TABLE | 1247 | 16543 | 0 | type | pg_toast | pg_toast_16539
| pg_toast.pg_toast_16539
2020-03-12 11:05:54.308963 | DROP TABLE | 1259 | 16544 | 0 | index | pg_toast | pg_toast_16539_inde
x | pg_toast.pg_toast_16539_index
2020-03-12 11:05:54.308963 | DROP TABLE | 2606 | 16546 | 0 | table constraint | public |
| pk_test02_cid_pid on public.tb_test02
2020-03-12 11:05:54.308963 | DROP TABLE | 1259 | 16545 | 0 | index | public | pk_test02_cid_pid
| public.pk_test02_cid_pid
2020-03-12 11:06:54.213763 | ALTER TABLE | 1259 | 16811 | 2 | table column | public |
| public.tb_drop_adit.name
(21 rows)
删除了数据库中的表以及测试表的字段name,在日志表中均能找到删除记录,并且还包含了表删除时附带删除的索引以及大文本存储的TOAST表。
修改事件触发器语法:
ALTER EVENT TRIGGER name DISABLE
ALTER EVENT TRIGGER name ENABLE [ REPLICA | ALWAYS ]
ALTER EVENT TRIGGER name OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
ALTER EVENT TRIGGER name RENAME TO new_name
禁止一个事件触发器使用 ”DISABLE“ 。
开启一个事件触发器使用 ”ENABLE“ 。