Postgresql学习笔记之——逻辑结构管理之触发器

触发器是一种由事件自动触发执行的特殊的存储过程,这些事件可以是对一个表进行的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表中的记录也被删除。

二、语句级触发器和行级触发器
1.语句级触发器

语句级触发器时指执行每个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)

2.行级触发器

删除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” 触发器是在语句结束时才触发的,行级别的 “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“ 。

你可能感兴趣的:(Postgresql)